1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "net_manager_constants.h"
17 #include "router_advertisement_daemon.h"
18 #include <csignal>
19 #include <net/if.h>
20 #include <sys/time.h>
21
22 namespace OHOS {
23 namespace NetManagerStandard {
24 namespace {
25 /** https://www.rfc-editor.org/rfc/rfc4861#section-6.2.1
26 * MaxRtrAdvInterval: MUST be no less than 4 seconds and no greater than 1800 seconds.
27 * Default: 600 seconds
28 * MinRtrAdvInterval: MUST be no less than 3seconds and no greater than 0.75 * MaxRtrAdvInterval.
29 * Default: 0.33 * MaxRtrAdvInterval If
30 * MaxRtrAdvInterval >= 9 seconds; otherwise, the
31 * Default is MaxRtrAdvInterval.
32 */
33 constexpr uint32_t MAX_URGENT_RTR_ADVERTISEMENTS = 10;
34 constexpr uint32_t RECV_RS_TIMEOUT = 1;
35 constexpr uint32_t SEND_RA_INTERVAL = 3000;
36 constexpr size_t RA_HEADER_SIZE = 16;
37
38 /**
39 * https://www.rfc-editor.org/rfc/rfc4861.html#section-6.1.2-4.2
40 * Note: If neither M nor O flags are set, this indicates that no
41 * information is available via DHCPv6.
42 */
43 constexpr uint8_t DEFAULT_ROUTER_PRE = 0x08;
44 constexpr uint8_t PREFIX_INFO_FLAGS = 0xc0;
45 constexpr uint32_t DEFAULT_HOP_LIMIT = 255;
46
47 /**
48 * https://tools.ietf.org/html/rfc4861#section-2.3
49 * all-nodes multicast address
50 * - the link-local scope address to reach all nodes,
51 * FF02::1.
52 */
53 constexpr const char *DST_IPV6 = "ff02::1";
54 } // namespace
55
RouterAdvertisementDaemon()56 RouterAdvertisementDaemon::RouterAdvertisementDaemon()
57 {
58 raParams_ = std::make_shared<RaParams>();
59 }
60
IsSocketValid()61 bool RouterAdvertisementDaemon::IsSocketValid()
62 {
63 return socket_ > 0;
64 }
65
HupRaThread()66 void RouterAdvertisementDaemon::HupRaThread()
67 {
68 stopRaThread_ = true;
69 }
70
Init(const std::string & ifaceName)71 int32_t RouterAdvertisementDaemon::Init(const std::string &ifaceName)
72 {
73 sendRaTimes_ = 0;
74 raParams_->name_ = ifaceName;
75 raParams_->index_ = if_nametoindex(ifaceName.c_str());
76 if (memset_s(&dstIpv6Addr_, sizeof(dstIpv6Addr_), 0, sizeof(dstIpv6Addr_)) != EOK) {
77 return NETMANAGER_EXT_ERR_MEMSET_FAIL;
78 }
79 dstIpv6Addr_.sin6_port = 0;
80 dstIpv6Addr_.sin6_family = AF_INET6;
81 dstIpv6Addr_.sin6_scope_id = 0;
82 inet_pton(AF_INET6, DST_IPV6, &dstIpv6Addr_.sin6_addr);
83 return NETMANAGER_EXT_SUCCESS;
84 }
85
StartRa()86 int32_t RouterAdvertisementDaemon::StartRa()
87 {
88 NETMGR_EXT_LOG_I("StartRa");
89 if (!CreateRASocket()) {
90 NETMGR_EXT_LOG_E("StartRa fail due to socket");
91 return NETMANAGER_EXT_ERR_PARAMETER_ERROR;
92 }
93 stopRaThread_ = false;
94 auto sp = shared_from_this();
95 recvRsThread_ = std::thread([sp]() { sp->RunRecvRsThread(); });
96 pthread_setname_np(recvRsThread_.native_handle(), "OH_Net_RecvRs");
97 recvRsThread_.detach();
98 ffrtTimer_.Start(SEND_RA_INTERVAL, [sp]() { sp->ProcessSendRaPacket(); });
99 return NETMANAGER_EXT_SUCCESS;
100 }
101
StopRa()102 void RouterAdvertisementDaemon::StopRa()
103 {
104 NETMGR_EXT_LOG_I("StopRa");
105 // close timer
106 ffrtTimer_.Stop();
107
108 HupRaThread();
109 CloseRaSocket();
110 }
111
CreateRASocket()112 bool RouterAdvertisementDaemon::CreateRASocket()
113 {
114 NETMGR_EXT_LOG_I("CreateRASocket Start");
115 socket_ = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
116 if (socket_ < 0) {
117 NETMGR_EXT_LOG_E("CreateRASocket fail, errno[%{public}d]", errno);
118 return false;
119 }
120 timeval timeout = {};
121 timeout.tv_sec = RECV_RS_TIMEOUT;
122 if (setsockopt(socket_, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) {
123 NETMGR_EXT_LOG_E("CreateRASocket setsockopt SO_RCVTIMEO fail");
124 close(socket_);
125 return false;
126 }
127 ifreq ifr = {};
128 if (strncpy_s(ifr.ifr_name, IFNAMSIZ - 1, raParams_->name_.c_str(), raParams_->name_.size()) != EOK) {
129 NETMGR_EXT_LOG_E("CreateRASocket strncopy fail");
130 close(socket_);
131 return false;
132 }
133 if (setsockopt(socket_, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) < 0) {
134 NETMGR_EXT_LOG_E("CreateRASocket setsockopt SO_BINDTODEVICE fail");
135 close(socket_);
136 return false;
137 }
138 uint32_t hoplimitNew = DEFAULT_HOP_LIMIT;
139 if (setsockopt(socket_, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (void *)&hoplimitNew, sizeof(hoplimitNew)) == -1) {
140 NETMGR_EXT_LOG_E(" setsockopt IPV6_UNICAST_HOPS fail");
141 }
142 return true;
143 }
144
CloseRaSocket()145 void RouterAdvertisementDaemon::CloseRaSocket()
146 {
147 NETMGR_EXT_LOG_I("CloseRaSocket Start");
148 if (socket_ > 0) {
149 close(socket_);
150 }
151 socket_ = -1;
152 }
153
MaybeSendRa(sockaddr_in6 & dest)154 bool RouterAdvertisementDaemon::MaybeSendRa(sockaddr_in6 &dest)
155 {
156 NETMGR_EXT_LOG_D("Send Ra Enter, socket_[%{public}d], raPacketLength_[%{public}hu]", socket_, raPacketLength_);
157 if (raPacketLength_ < RA_HEADER_SIZE) {
158 NETMGR_EXT_LOG_E("Send Ra failed due to Ra packet length less than RA header size");
159 return false;
160 }
161 if (!IsSocketValid()) {
162 NETMGR_EXT_LOG_E("Send Ra failed due to socket invalid");
163 return false;
164 }
165 int ret = sendto(socket_, raPacket_, raPacketLength_, 0, (sockaddr *)&dest, sizeof(dest));
166 if (ret < 0) {
167 NETMGR_EXT_LOG_E("Send Ra error, ret[%{public}d], errno[%{public}d]", ret, errno);
168 return false;
169 }
170 return true;
171 }
172
ProcessSendRaPacket()173 void RouterAdvertisementDaemon::ProcessSendRaPacket()
174 {
175 if (!IsSocketValid() || stopRaThread_) {
176 NETMGR_EXT_LOG_E("socket closed or stopRaThread!");
177 return;
178 }
179 if (AssembleRaLocked()) {
180 MaybeSendRa(dstIpv6Addr_);
181 }
182 ResetRaRetryInterval();
183 }
184
RunRecvRsThread()185 void RouterAdvertisementDaemon::RunRecvRsThread()
186 {
187 NETMGR_EXT_LOG_I("Start to receive Rs thread, socket[%{public}d]", socket_);
188 sockaddr_in6 solicitor = {};
189 uint8_t solicitation[IPV6_MIN_MTU] = {};
190 socklen_t sendLen = sizeof(solicitation);
191 while (IsSocketValid() && !stopRaThread_) {
192 if (memset_s(solicitation, sizeof(solicitation), 0, sizeof(solicitation)) != EOK) {
193 break;
194 }
195 auto rval =
196 recvfrom(socket_, solicitation, IPV6_MIN_MTU, 0, reinterpret_cast<sockaddr *>(&solicitor), &sendLen);
197 if (rval <= 0 && errno != EAGAIN && errno != EINTR) {
198 NETMGR_EXT_LOG_E("recvfrom failed, rval[%{public}zd], errno[%{public}d]", rval, errno);
199 break;
200 }
201 if (solicitation[0] != ICMPV6_ND_ROUTER_SOLICIT_TYPE) {
202 continue;
203 }
204 if (AssembleRaLocked()) {
205 MaybeSendRa(solicitor);
206 }
207 }
208 CloseRaSocket();
209 raParams_ = nullptr;
210 }
211
GetDeprecatedRaParams(RaParams & oldRa,RaParams & newRa)212 RaParams RouterAdvertisementDaemon::GetDeprecatedRaParams(RaParams &oldRa, RaParams &newRa)
213 {
214 RaParams deprecateRa = {};
215 for (auto ipp : newRa.prefixes_) {
216 if (oldRa.ContainsPrefix(ipp)) {
217 deprecateRa.prefixes_.emplace_back(ipp);
218 }
219 }
220 for (auto dns : newRa.dnses_) {
221 if (oldRa.ContainsDns(dns)) {
222 deprecateRa.dnses_.emplace_back(dns);
223 }
224 }
225 return deprecateRa;
226 }
227
BuildNewRa(const RaParams & newRa)228 void RouterAdvertisementDaemon::BuildNewRa(const RaParams &newRa)
229 {
230 raParams_->Set(newRa);
231 }
232
ResetRaRetryInterval()233 void RouterAdvertisementDaemon::ResetRaRetryInterval()
234 {
235 if (sendRaTimes_ < MAX_URGENT_RTR_ADVERTISEMENTS) {
236 sendRaTimes_++;
237 return;
238 }
239 if (sendRaTimes_ == MAX_URGENT_RTR_ADVERTISEMENTS) {
240 itimerval setvalue = {};
241 itimerval oldvalue = {};
242 setvalue.it_interval.tv_sec = DEFAULT_RTR_INTERVAL_SEC;
243 setvalue.it_value.tv_sec = 1;
244 sendRaTimes_++;
245 return;
246 }
247 }
248
AssembleRaLocked()249 bool RouterAdvertisementDaemon::AssembleRaLocked()
250 {
251 NETMGR_EXT_LOG_D("Generate Ra package start");
252 uint8_t raBuf[IPV6_MIN_MTU] = {};
253 uint8_t *ptr = raBuf;
254 uint16_t raHeadLen = PutRaHeader(ptr);
255 ptr += raHeadLen;
256 uint16_t raSllLen = PutRaSlla(ptr, raParams_->macAddr_);
257 ptr += raSllLen;
258 uint16_t raMtuLen = PutRaMtu(ptr, raParams_->mtu_);
259 ptr += raMtuLen;
260 uint16_t raPrefixLens = 0;
261 for (IpPrefix ipp : raParams_->prefixes_) {
262 uint16_t raPrefixLen = PutRaPio(ptr, ipp);
263 ptr += raPrefixLen;
264 raPrefixLens += raPrefixLen;
265 }
266 uint16_t raRdnsLen = PutRaRdnss(ptr);
267 ptr += raRdnsLen;
268 raPacketLength_ = raHeadLen + raSllLen + raMtuLen + raPrefixLens + raRdnsLen;
269 if (memset_s(&raPacket_, sizeof(raPacket_), 0, sizeof(raPacket_)) != EOK) {
270 return false;
271 }
272 if (memcpy_s(raPacket_, sizeof(raPacket_), raBuf, raPacketLength_) != EOK) {
273 return false;
274 }
275 NETMGR_EXT_LOG_D("Generate Ra package end, raPacketLength_: %{public}hu", raPacketLength_);
276 return true;
277 }
278
PutRaHeader(uint8_t * raBuf)279 uint16_t RouterAdvertisementDaemon::PutRaHeader(uint8_t *raBuf)
280 {
281 NETMGR_EXT_LOG_D("Append Ra header");
282 // https://datatracker.ietf.org/doc/html/rfc4861#section-4.2
283 // 0 1 2 3
284 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
285 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
286 // | Type | Code | Checksum |
287 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
288 // | Cur Hop Limit |M|O| Reserved | Router Lifetime |
289 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
290 // | Reachable Time |
291 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
292 // | Retrans Timer |
293 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
294 // | Options ...
295 // +-+-+-+-+-+-+-+-+-+-+-+-
296 Icmpv6HeadSt raHeadSt;
297 raHeadSt.type = ICMPV6_ND_ROUTER_ADVERT_TYPE;
298 raHeadSt.curHopLimit = DEFAULT_HOPLIMIT;
299 raHeadSt.flags = DEFAULT_ROUTER_PRE;
300 raHeadSt.routerLifetime = htons(DEFAULT_LIFETIME);
301 if (memcpy_s(raBuf, sizeof(Icmpv6HeadSt), &raHeadSt, sizeof(Icmpv6HeadSt)) != EOK) {
302 return 0;
303 }
304 return static_cast<uint16_t>(sizeof(Icmpv6HeadSt));
305 }
306
PutRaSlla(uint8_t * raBuf,const std::string & mac)307 uint16_t RouterAdvertisementDaemon::PutRaSlla(uint8_t *raBuf, const std::string &mac)
308 {
309 NETMGR_EXT_LOG_D("Append Ra source link lay address");
310 if (mac.size() < HW_MAC_STR_LENGTH) {
311 return 0;
312 }
313 // https://datatracker.ietf.org/doc/html/rfc4861#section-4.6.1
314 // 0 1 2 3
315 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
316 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
317 // | Type | Length | Link-Layer Address ...
318 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
319 Icmpv6SllOpt srcLinkAddrSt;
320 srcLinkAddrSt.type = ND_OPTION_SLLA_TYPE;
321 srcLinkAddrSt.len = sizeof(Icmpv6SllOpt) / UNITS_OF_OCTETS;
322 std::istringstream iss(mac);
323 int value = 0;
324 for (uint32_t i = 0; i < HW_MAC_LENGTH; i++) {
325 iss >> std::hex >> value;
326 srcLinkAddrSt.linkAddress[i] = static_cast<uint8_t>(value);
327 iss.ignore(1, ':');
328 }
329 if (memcpy_s(raBuf, sizeof(Icmpv6SllOpt), &srcLinkAddrSt, sizeof(Icmpv6SllOpt)) != EOK) {
330 return 0;
331 }
332 return static_cast<uint16_t>(sizeof(Icmpv6SllOpt));
333 }
334
PutRaMtu(uint8_t * raBuf,int32_t mtu)335 uint16_t RouterAdvertisementDaemon::PutRaMtu(uint8_t *raBuf, int32_t mtu)
336 {
337 NETMGR_EXT_LOG_D("Append Ra Mtu option");
338 // https://datatracker.ietf.org/doc/html/rfc4861#section-4.6.4
339 // 0 1 2 3
340 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
341 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
342 // | Type | Length | Reserved |
343 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
344 // | MTU |
345 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
346 Icmpv6MtuOpt mtuSt;
347 mtuSt.type = ND_OPTION_MTU_TYPE;
348 mtuSt.len = sizeof(Icmpv6MtuOpt) / UNITS_OF_OCTETS;
349 mtuSt.mtu = static_cast<uint32_t>(htonl(mtu));
350 if (memcpy_s(raBuf, sizeof(Icmpv6MtuOpt), &mtuSt, sizeof(Icmpv6MtuOpt)) != EOK) {
351 return 0;
352 }
353 return static_cast<uint16_t>(sizeof(Icmpv6MtuOpt));
354 }
355
PutRaPio(uint8_t * raBuf,IpPrefix & ipp)356 uint16_t RouterAdvertisementDaemon::PutRaPio(uint8_t *raBuf, IpPrefix &ipp)
357 {
358 NETMGR_EXT_LOG_D("Append Ra prefix information option");
359 // refer to https://tools.ietf.org/html/rfc4861#section-4.6.2
360 // 0 1 2 3
361 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
362 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
363 // | Type | Length | Prefix Length |L|A| Reserved1 |
364 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
365 // | Valid Lifetime |
366 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
367 // | Preferred Lifetime |
368 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
369 // | Reserved2 |
370 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
371 // | |
372 // + +
373 // | |
374 // + Prefix +
375 // | |
376 // + +
377 // | |
378 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
379 Icmpv6PrefixInfoOpt prefixInfoSt;
380 prefixInfoSt.type = ND_OPTION_PIO_TYPE;
381 prefixInfoSt.len = sizeof(Icmpv6PrefixInfoOpt) / UNITS_OF_OCTETS;
382 prefixInfoSt.prefixLen = ipp.prefixesLength;
383 prefixInfoSt.flag = PREFIX_INFO_FLAGS;
384 prefixInfoSt.validLifetime = htonl(DEFAULT_LIFETIME);
385 prefixInfoSt.prefLifetime = htonl(DEFAULT_LIFETIME);
386 prefixInfoSt.type = ND_OPTION_PIO_TYPE;
387 if (memcpy_s(prefixInfoSt.prefix, IPV6_ADDR_LEN, ipp.prefix.s6_addr, IPV6_ADDR_LEN) != EOK) {
388 return 0;
389 }
390 if (memcpy_s(raBuf, sizeof(Icmpv6PrefixInfoOpt), &prefixInfoSt, sizeof(Icmpv6PrefixInfoOpt)) != EOK) {
391 return 0;
392 }
393 return static_cast<uint16_t>(sizeof(Icmpv6PrefixInfoOpt));
394 }
395
PutRaRdnss(uint8_t * raBuf)396 uint16_t RouterAdvertisementDaemon::PutRaRdnss(uint8_t *raBuf)
397 {
398 NETMGR_EXT_LOG_D("Make RA DNS server option");
399 // https://datatracker.ietf.org/doc/rfc8106/
400 // 0 1 2 3
401 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
402 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
403 // | Type | Length | Reserved |
404 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
405 // | Lifetime |
406 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
407 // | |
408 // : Addresses of IPv6 Recursive DNS Servers :
409 // | |
410 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
411 Icmpv6RdnsOpt rdnsInfoSt;
412 size_t raRdnsNum = raParams_->prefixes_.size();
413 rdnsInfoSt.type = ND_OPTION_RDNSS_TYPE;
414 rdnsInfoSt.len = (sizeof(Icmpv6RdnsOpt) + raRdnsNum * IPV6_ADDR_LEN) / UNITS_OF_OCTETS;
415 rdnsInfoSt.lifetime = htonl(DEFAULT_LIFETIME);
416 if (memcpy_s(raBuf, sizeof(Icmpv6RdnsOpt), &rdnsInfoSt, sizeof(Icmpv6RdnsOpt)) != EOK) {
417 return 0;
418 }
419 raBuf += sizeof(Icmpv6RdnsOpt);
420 uint32_t index = 0;
421 for (IpPrefix ipp : raParams_->prefixes_) {
422 if (memcpy_s(raBuf + index * IPV6_ADDR_LEN, IPV6_ADDR_LEN, ipp.address.s6_addr, IPV6_ADDR_LEN) != EOK) {
423 return 0;
424 }
425 index++;
426 }
427 return static_cast<uint16_t>(sizeof(Icmpv6RdnsOpt) + raRdnsNum * IPV6_ADDR_LEN);
428 }
429 } // namespace NetManagerStandard
430 } // namespace OHOS
431