• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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