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 128 : bool IsCurrentInterfaceUsable(T & iterator)
29 : {
30 128 : if (!iterator.IsUp())
31 : {
32 0 : return false; // not a usable interface
33 : }
34 : char name[chip::Inet::InterfaceId::kMaxIfNameLength];
35 128 : 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 128 : if (strncmp(name, "lo", 2) == 0)
50 : {
51 : /// local loopback interface is not usable by MDNS
52 64 : return false;
53 : }
54 64 : return true;
55 : }
56 :
57 : class AllInterfaces : public mdns::Minimal::ListenIterator
58 : {
59 : public:
60 64 : AllInterfaces() { SkipToFirstValidInterface(); }
61 :
62 192 : bool Next(chip::Inet::InterfaceId * id, chip::Inet::IPAddressType * type) override
63 : {
64 192 : if (!mIterator.HasCurrent())
65 : {
66 64 : return false;
67 : }
68 :
69 : #if INET_CONFIG_ENABLE_IPV4
70 128 : if (mState == State::kIpV4)
71 : {
72 64 : mState = State::kIpV6;
73 :
74 64 : if (CurrentInterfaceHasAddressOfType(chip::Inet::IPAddressType::kIPv4))
75 : {
76 64 : *id = mIterator.GetInterfaceId();
77 64 : *type = chip::Inet::IPAddressType::kIPv4;
78 64 : return true;
79 : }
80 : }
81 : #endif
82 :
83 : #if INET_CONFIG_ENABLE_IPV4
84 64 : mState = State::kIpV4;
85 : #endif
86 :
87 64 : bool haveResult = CurrentInterfaceHasAddressOfType(chip::Inet::IPAddressType::kIPv6);
88 64 : if (haveResult)
89 : {
90 64 : *id = mIterator.GetInterfaceId();
91 64 : *type = chip::Inet::IPAddressType::kIPv6;
92 : }
93 :
94 64 : for (mIterator.Next(); SkipCurrentInterface(); mIterator.Next())
95 : {
96 : }
97 :
98 64 : if (haveResult)
99 : {
100 64 : 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 128 : void SkipToFirstValidInterface()
118 : {
119 : do
120 : {
121 128 : if (!SkipCurrentInterface())
122 : {
123 64 : break;
124 : }
125 64 : } while (mIterator.Next());
126 64 : }
127 :
128 192 : bool SkipCurrentInterface()
129 : {
130 192 : if (!mIterator.HasCurrent())
131 : {
132 64 : return false; // nothing to try.
133 : }
134 :
135 128 : 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 400 : AllAddressesIterator(chip::Inet::InterfaceId interfaceId, chip::Inet::IPAddressType addrType) :
145 400 : mInterfaceIdFilter(interfaceId), mAddrType(addrType)
146 400 : {}
147 :
148 1244 : bool Next(chip::Inet::IPAddress & dest)
149 : {
150 : while (true)
151 : {
152 1244 : if (!mIterator.HasCurrent())
153 : {
154 438 : return false;
155 : }
156 :
157 1072 : if (mIterator.GetInterfaceId() != mInterfaceIdFilter)
158 : {
159 604 : mIterator.Next();
160 604 : continue;
161 : }
162 :
163 468 : CHIP_ERROR err = mIterator.GetAddress(dest);
164 468 : mIterator.Next();
165 :
166 468 : if (mAddrType != chip::Inet::IPAddressType::kAny)
167 : {
168 468 : if (dest.Type() != mAddrType)
169 : {
170 202 : continue;
171 : }
172 : }
173 :
174 266 : 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 266 : return true;
181 806 : }
182 : }
183 :
184 : private:
185 : const chip::Inet::InterfaceId mInterfaceIdFilter;
186 : const chip::Inet::IPAddressType mAddrType;
187 : chip::Inet::InterfaceAddressIterator mIterator;
188 : };
189 :
190 128 : bool AllInterfaces::CurrentInterfaceHasAddressOfType(chip::Inet::IPAddressType type)
191 : {
192 : // mIterator.HasCurrent() must be true here.
193 128 : AllAddressesIterator addressIter(mIterator.GetInterfaceId(), type);
194 : chip::Inet::IPAddress addr;
195 128 : if (addressIter.Next(addr))
196 : {
197 128 : return true;
198 : }
199 :
200 0 : return false;
201 128 : }
202 :
203 : class DefaultAddressPolicy : public AddressPolicy
204 : {
205 : public:
206 64 : chip::Platform::UniquePtr<ListenIterator> GetListenEndpoints() override
207 : {
208 64 : return chip::Platform::UniquePtr<ListenIterator>(chip::Platform::New<AllInterfaces>());
209 : }
210 :
211 272 : chip::Platform::UniquePtr<IpAddressIterator> GetIpAddressesForEndpoint(chip::Inet::InterfaceId interfaceId,
212 : chip::Inet::IPAddressType type) override
213 : {
214 272 : return chip::Platform::UniquePtr<IpAddressIterator>(chip::Platform::New<AllAddressesIterator>(interfaceId, type));
215 : }
216 : };
217 :
218 : DefaultAddressPolicy gDefaultAddressPolicy;
219 :
220 : } // namespace
221 :
222 65 : void SetDefaultAddressPolicy()
223 : {
224 65 : SetAddressPolicy(&gDefaultAddressPolicy);
225 65 : }
226 :
227 : } // namespace Minimal
228 : } // namespace mdns
|