Line data Source code
1 : /* 2 : * 3 : * Copyright (c) 2022 Project CHIP Authors 4 : * 5 : * Licensed under the Apache License, Version 2.0 (the "License"); 6 : * you may not use this file except in compliance with the License. 7 : * You may obtain a copy of the License at 8 : * 9 : * http://www.apache.org/licenses/LICENSE-2.0 10 : * 11 : * Unless required by applicable law or agreed to in writing, software 12 : * distributed under the License is distributed on an "AS IS" BASIS, 13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 : * See the License for the specific language governing permissions and 15 : * limitations under the License. 16 : */ 17 : #include <lib/dnssd/minimal_mdns/AddressPolicy.h> 18 : 19 : #include <lib/support/logging/CHIPLogging.h> 20 : 21 : namespace mdns { 22 : namespace Minimal { 23 : namespace { 24 : 25 : /// Checks if the current interface is powered on 26 : /// and not local loopback. 27 : template <typename T> 28 148 : bool IsCurrentInterfaceUsable(T & iterator) 29 : { 30 148 : if (!iterator.IsUp()) 31 : { 32 0 : return false; // not a usable interface 33 : } 34 : char name[chip::Inet::InterfaceId::kMaxIfNameLength]; 35 148 : if (iterator.GetInterfaceName(name, sizeof(name)) != CHIP_NO_ERROR) 36 : { 37 0 : ChipLogError(Discovery, "Failed to get interface name."); 38 0 : return false; 39 : } 40 : 41 : // TODO: need a better way to ignore local loopback interfaces/addresses 42 : // We do not want to listen on local loopback even though they are up and 43 : // support multicast 44 : // 45 : // Some way to detect 'is local looback' that is smarter (e.g. at least 46 : // strict string compare on linux instead of substring) would be better. 47 : // 48 : // This would reject likely valid interfaces like 'lollipop' or 'lostinspace' 49 148 : if (strncmp(name, "lo", 2) == 0) 50 : { 51 : /// local loopback interface is not usable by MDNS 52 74 : return false; 53 : } 54 74 : return true; 55 : } 56 : 57 : class AllInterfaces : public mdns::Minimal::ListenIterator 58 : { 59 : public: 60 74 : AllInterfaces() { SkipToFirstValidInterface(); } 61 : 62 222 : bool Next(chip::Inet::InterfaceId * id, chip::Inet::IPAddressType * type) override 63 : { 64 222 : if (!mIterator.HasCurrent()) 65 : { 66 74 : return false; 67 : } 68 : 69 : #if INET_CONFIG_ENABLE_IPV4 70 148 : if (mState == State::kIpV4) 71 : { 72 74 : mState = State::kIpV6; 73 : 74 74 : if (CurrentInterfaceHasAddressOfType(chip::Inet::IPAddressType::kIPv4)) 75 : { 76 74 : *id = mIterator.GetInterfaceId(); 77 74 : *type = chip::Inet::IPAddressType::kIPv4; 78 74 : return true; 79 : } 80 : } 81 : #endif 82 : 83 : #if INET_CONFIG_ENABLE_IPV4 84 74 : mState = State::kIpV4; 85 : #endif 86 : 87 74 : bool haveResult = CurrentInterfaceHasAddressOfType(chip::Inet::IPAddressType::kIPv6); 88 74 : if (haveResult) 89 : { 90 74 : *id = mIterator.GetInterfaceId(); 91 74 : *type = chip::Inet::IPAddressType::kIPv6; 92 : } 93 : 94 74 : for (mIterator.Next(); SkipCurrentInterface(); mIterator.Next()) 95 : { 96 : } 97 : 98 74 : if (haveResult) 99 : { 100 74 : return true; 101 : } 102 : 103 0 : return Next(id, type); 104 : } 105 : 106 : private: 107 : #if INET_CONFIG_ENABLE_IPV4 108 : enum class State 109 : { 110 : kIpV4, 111 : kIpV6, 112 : }; 113 : State mState = State::kIpV4; 114 : #endif 115 : chip::Inet::InterfaceIterator mIterator; 116 : 117 148 : void SkipToFirstValidInterface() 118 : { 119 : do 120 : { 121 148 : if (!SkipCurrentInterface()) 122 : { 123 74 : break; 124 : } 125 74 : } while (mIterator.Next()); 126 74 : } 127 : 128 222 : bool SkipCurrentInterface() 129 : { 130 222 : if (!mIterator.HasCurrent()) 131 : { 132 74 : return false; // nothing to try. 133 : } 134 : 135 148 : return !IsCurrentInterfaceUsable(mIterator); 136 : } 137 : 138 : bool CurrentInterfaceHasAddressOfType(chip::Inet::IPAddressType type); 139 : }; 140 : 141 : class AllAddressesIterator : public mdns::Minimal::IpAddressIterator 142 : { 143 : public: 144 446 : AllAddressesIterator(chip::Inet::InterfaceId interfaceId, chip::Inet::IPAddressType addrType) : 145 446 : mInterfaceIdFilter(interfaceId), mAddrType(addrType) 146 446 : {} 147 : 148 1364 : bool Next(chip::Inet::IPAddress & dest) 149 : { 150 : while (true) 151 : { 152 1364 : if (!mIterator.HasCurrent()) 153 : { 154 482 : return false; 155 : } 156 : 157 1180 : if (mIterator.GetInterfaceId() != mInterfaceIdFilter) 158 : { 159 658 : mIterator.Next(); 160 658 : continue; 161 : } 162 : 163 522 : CHIP_ERROR err = mIterator.GetAddress(dest); 164 522 : mIterator.Next(); 165 : 166 522 : if (mAddrType != chip::Inet::IPAddressType::kAny) 167 : { 168 522 : if (dest.Type() != mAddrType) 169 : { 170 224 : continue; 171 : } 172 : } 173 : 174 298 : if (err != CHIP_NO_ERROR) 175 : { 176 0 : ChipLogError(Discovery, "Failed to fetch interface IP address: %" CHIP_ERROR_FORMAT, err.Format()); 177 0 : continue; 178 : } 179 : 180 298 : return true; 181 882 : } 182 : } 183 : 184 : private: 185 : const chip::Inet::InterfaceId mInterfaceIdFilter; 186 : const chip::Inet::IPAddressType mAddrType; 187 : chip::Inet::InterfaceAddressIterator mIterator; 188 : }; 189 : 190 148 : bool AllInterfaces::CurrentInterfaceHasAddressOfType(chip::Inet::IPAddressType type) 191 : { 192 : // mIterator.HasCurrent() must be true here. 193 148 : AllAddressesIterator addressIter(mIterator.GetInterfaceId(), type); 194 : chip::Inet::IPAddress addr; 195 148 : if (addressIter.Next(addr)) 196 : { 197 148 : return true; 198 : } 199 : 200 0 : return false; 201 148 : } 202 : 203 : class DefaultAddressPolicy : public AddressPolicy 204 : { 205 : public: 206 74 : chip::Platform::UniquePtr<ListenIterator> GetListenEndpoints() override 207 : { 208 74 : return chip::Platform::UniquePtr<ListenIterator>(chip::Platform::New<AllInterfaces>()); 209 : } 210 : 211 298 : chip::Platform::UniquePtr<IpAddressIterator> GetIpAddressesForEndpoint(chip::Inet::InterfaceId interfaceId, 212 : chip::Inet::IPAddressType type) override 213 : { 214 298 : return chip::Platform::UniquePtr<IpAddressIterator>(chip::Platform::New<AllAddressesIterator>(interfaceId, type)); 215 : } 216 : }; 217 : 218 : DefaultAddressPolicy gDefaultAddressPolicy; 219 : 220 : } // namespace 221 : 222 31 : void SetDefaultAddressPolicy() 223 : { 224 31 : SetAddressPolicy(&gDefaultAddressPolicy); 225 31 : } 226 : 227 : } // namespace Minimal 228 : } // namespace mdns