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 214 : bool IsCurrentInterfaceUsable(T & iterator)
29 : {
30 214 : if (!iterator.IsUp())
31 : {
32 0 : return false; // not a usable interface
33 : }
34 : char name[chip::Inet::InterfaceId::kMaxIfNameLength];
35 428 : 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 214 : if (strncmp(name, "lo", 2) == 0)
50 : {
51 : /// local loopback interface is not usable by MDNS
52 107 : return false;
53 : }
54 :
55 : // skip IEEE 802.15.4 / Thread interfaces — not suitable for mDNS
56 107 : if (strncmp(name, "wpan", 4) == 0)
57 : {
58 0 : return false;
59 : }
60 :
61 107 : return true;
62 : }
63 :
64 : class AllInterfaces : public mdns::Minimal::ListenIterator
65 : {
66 : public:
67 107 : AllInterfaces() { SkipToFirstValidInterface(); }
68 :
69 321 : bool Next(chip::Inet::InterfaceId * id, chip::Inet::IPAddressType * type) override
70 : {
71 321 : if (!mIterator.HasCurrent())
72 : {
73 107 : return false;
74 : }
75 :
76 : #if INET_CONFIG_ENABLE_IPV4
77 214 : if (mState == State::kIpV4)
78 : {
79 107 : mState = State::kIpV6;
80 :
81 107 : if (CurrentInterfaceHasAddressOfType(chip::Inet::IPAddressType::kIPv4))
82 : {
83 107 : *id = mIterator.GetInterfaceId();
84 107 : *type = chip::Inet::IPAddressType::kIPv4;
85 107 : return true;
86 : }
87 : }
88 : #endif
89 :
90 : #if INET_CONFIG_ENABLE_IPV4
91 107 : mState = State::kIpV4;
92 : #endif
93 :
94 107 : bool haveResult = CurrentInterfaceHasAddressOfType(chip::Inet::IPAddressType::kIPv6);
95 107 : if (haveResult)
96 : {
97 107 : *id = mIterator.GetInterfaceId();
98 107 : *type = chip::Inet::IPAddressType::kIPv6;
99 : }
100 :
101 107 : for (mIterator.Next(); SkipCurrentInterface(); mIterator.Next())
102 : {
103 : }
104 :
105 107 : if (haveResult)
106 : {
107 107 : return true;
108 : }
109 :
110 0 : return Next(id, type);
111 : }
112 :
113 : private:
114 : #if INET_CONFIG_ENABLE_IPV4
115 : enum class State
116 : {
117 : kIpV4,
118 : kIpV6,
119 : };
120 : State mState = State::kIpV4;
121 : #endif
122 : chip::Inet::InterfaceIterator mIterator;
123 :
124 214 : void SkipToFirstValidInterface()
125 : {
126 : do
127 : {
128 214 : if (!SkipCurrentInterface())
129 : {
130 107 : break;
131 : }
132 107 : } while (mIterator.Next());
133 107 : }
134 :
135 321 : bool SkipCurrentInterface()
136 : {
137 321 : if (!mIterator.HasCurrent())
138 : {
139 107 : return false; // nothing to try.
140 : }
141 :
142 214 : return !IsCurrentInterfaceUsable(mIterator);
143 : }
144 :
145 : bool CurrentInterfaceHasAddressOfType(chip::Inet::IPAddressType type);
146 : };
147 :
148 : class AllAddressesIterator : public mdns::Minimal::IpAddressIterator
149 : {
150 : public:
151 528 : AllAddressesIterator(chip::Inet::InterfaceId interfaceId, chip::Inet::IPAddressType addrType) :
152 528 : mInterfaceIdFilter(interfaceId), mAddrType(addrType)
153 528 : {}
154 :
155 1412 : bool Next(chip::Inet::IPAddress & dest)
156 : {
157 : while (true)
158 : {
159 1412 : if (!mIterator.HasCurrent())
160 : {
161 488 : return false;
162 : }
163 :
164 1258 : if (mIterator.GetInterfaceId() != mInterfaceIdFilter)
165 : {
166 697 : mIterator.Next();
167 697 : continue;
168 : }
169 :
170 561 : CHIP_ERROR err = mIterator.GetAddress(dest);
171 561 : mIterator.Next();
172 :
173 561 : if (mAddrType != chip::Inet::IPAddressType::kAny)
174 : {
175 561 : if (dest.Type() != mAddrType)
176 : {
177 227 : continue;
178 : }
179 : }
180 :
181 668 : if (err != CHIP_NO_ERROR)
182 : {
183 0 : ChipLogError(Discovery, "Failed to fetch interface IP address: %" CHIP_ERROR_FORMAT, err.Format());
184 0 : continue;
185 : }
186 :
187 334 : return true;
188 924 : }
189 : }
190 :
191 : private:
192 : const chip::Inet::InterfaceId mInterfaceIdFilter;
193 : const chip::Inet::IPAddressType mAddrType;
194 : chip::Inet::InterfaceAddressIterator mIterator;
195 : };
196 :
197 214 : bool AllInterfaces::CurrentInterfaceHasAddressOfType(chip::Inet::IPAddressType type)
198 : {
199 : // mIterator.HasCurrent() must be true here.
200 214 : AllAddressesIterator addressIter(mIterator.GetInterfaceId(), type);
201 : chip::Inet::IPAddress addr;
202 214 : if (addressIter.Next(addr))
203 : {
204 214 : return true;
205 : }
206 :
207 0 : return false;
208 214 : }
209 :
210 : class DefaultAddressPolicy : public AddressPolicy
211 : {
212 : public:
213 107 : chip::Platform::UniquePtr<ListenIterator> GetListenEndpoints() override
214 : {
215 107 : return chip::Platform::UniquePtr<ListenIterator>(chip::Platform::New<AllInterfaces>());
216 : }
217 :
218 314 : chip::Platform::UniquePtr<IpAddressIterator> GetIpAddressesForEndpoint(chip::Inet::InterfaceId interfaceId,
219 : chip::Inet::IPAddressType type) override
220 : {
221 314 : return chip::Platform::UniquePtr<IpAddressIterator>(chip::Platform::New<AllAddressesIterator>(interfaceId, type));
222 : }
223 : };
224 :
225 : DefaultAddressPolicy gDefaultAddressPolicy;
226 :
227 : } // namespace
228 :
229 183 : void SetDefaultAddressPolicy()
230 : {
231 183 : SetAddressPolicy(&gDefaultAddressPolicy);
232 183 : }
233 :
234 : } // namespace Minimal
235 : } // namespace mdns
|