1 /*
2  * Copyright (c) 2021-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 "clatd.h"
17 
18 #include <arpa/inet.h>
19 #include <cerrno>
20 #include <climits>
21 #include <cstdlib>
22 #include <linux/if_packet.h>
23 #include <net/if.h>
24 #include <netinet/icmp6.h>
25 #include <netinet/in.h>
26 #include <netinet/ip6.h>
27 #include <poll.h>
28 #include <string>
29 #include <sys/eventfd.h>
30 #include <sys/socket.h>
31 #include <thread>
32 #include <unistd.h>
33 #include <vector>
34 
35 #include "clat_constants.h"
36 #include "clat_utils.h"
37 #include "clatd_packet_converter.h"
38 #include "ffrt.h"
39 #include "ffrt_inner.h"
40 #include "ffrt_timer.h"
41 #include "net_manager_constants.h"
42 #include "netnative_log_wrapper.h"
43 
44 namespace OHOS {
45 namespace nmd {
46 using namespace OHOS::NetManagerStandard;
Clatd(int tunFd,int readSock6,int writeSock6,const std::string & v6Iface,const std::string & prefixAddrStr,const std::string & v4AddrStr,const std::string & v6AddrStr)47 Clatd::Clatd(int tunFd, int readSock6, int writeSock6, const std::string &v6Iface, const std::string &prefixAddrStr,
48              const std::string &v4AddrStr, const std::string &v6AddrStr)
49     : tunFd_(tunFd), readSock6_(readSock6), writeSock6_(writeSock6), v6Iface_(v6Iface)
50 {
51     stopFd_ = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
52     tunIface_ = std::string(CLAT_PREFIX) + v6Iface;
53     inet_pton(AF_INET6, v6AddrStr.c_str(), &v6Addr_);
54     inet_pton(AF_INET, v4AddrStr.c_str(), &v4Addr_.s_addr);
55     inet_pton(AF_INET6, prefixAddrStr.c_str(), &prefixAddr_);
56     isSocketClosed_ = false;
57     stopStatus_ = true;
58 }
59 
~Clatd()60 Clatd::~Clatd()
61 {
62     close(stopFd_);
63 }
64 
Start()65 void Clatd::Start()
66 {
67     if (!stopStatus_) {
68         NETNATIVE_LOGW("fail to start clatd, clatd for %{public}s is already running", v6Iface_.c_str());
69         return;
70     }
71     SendDadPacket();
72     stopStatus_ = false;
73     std::thread([this]() { RunLoop(); }).detach();
74 }
75 
Stop()76 void Clatd::Stop()
77 {
78     if (stopStatus_) {
79         NETNATIVE_LOGW("fail to stop clatd, clatd for %{public}s is not running", v6Iface_.c_str());
80         return;
81     }
82     uint64_t one = 1;
83     write(stopFd_, &one, sizeof(one));
84 
85     std::unique_lock<ffrt::mutex> lck(mutex_);
86     cv_.wait(lck, [this] { return stopStatus_ == true; });
87 };
88 
SendDadPacket()89 void Clatd::SendDadPacket()
90 {
91     ClatdDadPacket dadPacket;
92 
93     dadPacket.v6Header.ip6_vfc = IPV6_VERSION_FLAG;
94     dadPacket.v6Header.ip6_plen = htons(sizeof(ClatdDadPacket) - sizeof(ip6_hdr));
95     dadPacket.v6Header.ip6_nxt = IPPROTO_ICMPV6;
96     dadPacket.v6Header.ip6_hlim = 0xff;
97     inet_pton(AF_INET6, "::", &dadPacket.v6Header.ip6_src);
98     inet_pton(AF_INET6, SOLICITED_NODE_PREFIX, &dadPacket.v6Header.ip6_dst);
99     size_t v6AddrByteLen = V6ADDR_BIT_LEN / CHAR_BIT;
100     for (size_t i = SOLICITED_NODE_SUFFIX_OFFSET; i < v6AddrByteLen; i++) {
101         dadPacket.v6Header.ip6_dst.s6_addr[i] = v6Addr_.s6_addr[i];
102     }
103 
104     dadPacket.ns.nd_ns_type = ND_NEIGHBOR_SOLICIT;
105     dadPacket.ns.nd_ns_code = 0;
106     dadPacket.ns.nd_ns_reserved = 0;
107     dadPacket.ns.nd_ns_target = v6Addr_;
108     uint32_t checkSum = dadPacket.v6Header.ip6_plen + htons(dadPacket.v6Header.ip6_nxt);
109     checkSum = AddChecksum(checkSum, &dadPacket.v6Header.ip6_src, sizeof(dadPacket) - IPV6_SRC_OFFSET);
110     dadPacket.ns.nd_ns_cksum = ~Checksum32To16(checkSum);
111 
112     dadPacket.nonceOptType = NDP_NOUNCE_OPT;
113     dadPacket.nonceOptLen = 1;
114     arc4random_buf(&dadPacket.nonce, sizeof(dadPacket.nonce));
115 
116     sockaddr_in6 dstAddr;
117     dstAddr.sin6_family = AF_INET6;
118     dstAddr.sin6_addr = dadPacket.v6Header.ip6_dst;
119     dstAddr.sin6_scope_id = if_nametoindex(v6Iface_.c_str());
120 
121     sendto(writeSock6_, &dadPacket, sizeof(dadPacket), 0, reinterpret_cast<const sockaddr *>(&dstAddr),
122            sizeof(dstAddr));
123 }
124 
RunLoop()125 void Clatd::RunLoop()
126 {
127     pollfd fds[] = {
128         {stopFd_, POLLIN, 0},
129         {readSock6_, POLLIN, 0},
130         {tunFd_, POLLIN, 0},
131     };
132     enum clatdFds {
133         EVENT_STOP,
134         READ_V6,
135         READ_V4,
136     };
137     FfrtTimer timerClatdRunning;
138     timerClatdRunning.Start(CLATD_TIMER_CYCLE_MS, []() { NETNATIVE_LOGI("Clatd is running loop"); });
139     while (!isSocketClosed_) {
140         if (poll(fds, sizeof(fds) / sizeof((fds)[0]), -1) == -1) {
141             if (errno != EINTR) {
142                 NETNATIVE_LOGW("event_loop/poll returned an error, errno: %{public}d", errno);
143             }
144         } else {
145             if (fds[EVENT_STOP].revents) {
146                 uint64_t one = 1;
147                 read(stopFd_, &one, sizeof one);
148                 std::unique_lock<ffrt::mutex> lck(mutex_);
149                 stopStatus_ = true;
150                 cv_.notify_one();
151                 break;
152             }
153             if (fds[READ_V6].revents) {
154                 ProcessV6Packet();
155             }
156             if (fds[READ_V4].revents) {
157                 ProcessV4Packet();
158             }
159         }
160     }
161     timerClatdRunning.Stop();
162 }
163 
MaybeCalculateL4Checksum(int packetLen,ClatdReadV6Buf & readBuf)164 int32_t Clatd::MaybeCalculateL4Checksum(int packetLen, ClatdReadV6Buf &readBuf)
165 {
166     const int csumStart = readBuf.vnet.csumStart;
167     const int csumOffset = csumStart + readBuf.vnet.csumOffset;
168     if (csumOffset > packetLen) {
169         NETNATIVE_LOGW("csum offset %{public}d larger than packet length %{public}d", csumOffset, packetLen);
170         return NETMANAGER_ERR_INVALID_PARAMETER;
171     }
172     uint16_t csum = CalChecksum(readBuf.payload, packetLen); // L4 checksum calculation required
173     if (csum == 0) {
174         csum = 0xFFFF;
175     }
176     readBuf.payload[csumOffset] = csum & 0xFF;
177     readBuf.payload[csumOffset + 1] = csum >> CHAR_BIT;
178     return NETMANAGER_SUCCESS;
179 }
180 
ProcessV6Packet()181 void Clatd::ProcessV6Packet()
182 {
183     ClatdReadV6Buf readBuf;
184     iovec iov;
185     iov.iov_base = &readBuf;
186     iov.iov_len = sizeof(readBuf);
187 
188     char cmsgBuf[CMSG_SPACE(sizeof(tpacket_auxdata))];
189     msghdr msgHdr;
190     msgHdr.msg_iov = &iov;
191     msgHdr.msg_iovlen = 1;
192     msgHdr.msg_control = cmsgBuf;
193     msgHdr.msg_controllen = sizeof(cmsgBuf);
194 
195     ssize_t readLen;
196     if (ReadV6Packet(msgHdr, readLen) != NETMANAGER_SUCCESS) {
197         return;
198     }
199 
200     uint32_t tpStatus = 0;
201     uint16_t tpNet = 0;
202     for (cmsghdr *cmsgHdr = CMSG_FIRSTHDR(&msgHdr); cmsgHdr != NULL; cmsgHdr = CMSG_NXTHDR(&msgHdr, cmsgHdr)) {
203         if (cmsgHdr->cmsg_level == SOL_PACKET && cmsgHdr->cmsg_type == PACKET_AUXDATA) {
204             tpacket_auxdata *auxData = reinterpret_cast<tpacket_auxdata *>(CMSG_DATA(cmsgHdr));
205             tpStatus = auxData->tp_status;
206             tpNet = auxData->tp_net;
207             break;
208         }
209     }
210 
211     if (static_cast<size_t>(readLen) < offsetof(ClatdReadV6Buf, payload) + tpNet) {
212         NETNATIVE_LOGW("%{public}zd read packet len shorter than %{public}u L2 header", readLen, tpNet);
213         return;
214     }
215 
216     int packetLen = readLen - offsetof(ClatdReadV6Buf, payload);
217     bool skip_csum = false;
218     if ((tpStatus & TP_STATUS_CSUMNOTREADY) || (tpStatus & TP_STATUS_CSUM_VALID)) {
219         NETNATIVE_LOGW("skip csum for packet which length is %{public}zd", readLen);
220         skip_csum = true;
221     }
222 
223     ClatdPacketConverter converter = ClatdPacketConverter(readBuf.payload + tpNet, packetLen - tpNet,
224                                                           CONVERT_FROM_V6_TO_V4, v4Addr_, v6Addr_, prefixAddr_);
225     if (converter.ConvertPacket(skip_csum) != NETMANAGER_SUCCESS) {
226         return;
227     }
228     std::vector<iovec> iovPackets(CLATD_MAX);
229     int effectivePos = 0;
230     converter.GetConvertedPacket(iovPackets, effectivePos);
231     if (effectivePos > 0) {
232         writev(tunFd_, &iovPackets[0], effectivePos);
233     }
234 }
235 
ProcessV4Packet()236 void Clatd::ProcessV4Packet()
237 {
238     ClatdReadTunBuf readBuf;
239     ssize_t readLen;
240     if (ReadV4Packet(readBuf, readLen) != NETMANAGER_SUCCESS) {
241         return;
242     }
243 
244     const int payloadOffset = offsetof(ClatdReadTunBuf, payload);
245     if (readLen < payloadOffset) {
246         NETNATIVE_LOGW("%{public}zd read packet len shorter than %{public}d payload offset", readLen, payloadOffset);
247         return;
248     }
249 
250     const int packetLen = readLen - payloadOffset;
251 
252     uint16_t tunProtocol = ntohs(readBuf.tunProtocolInfo.proto);
253     if (tunProtocol != ETH_P_IP) {
254         NETNATIVE_LOGW("unknown packet type = 0x%{public}x", tunProtocol);
255         return;
256     }
257 
258     if (readBuf.tunProtocolInfo.flags != 0) {
259         NETNATIVE_LOGW("unexpected flags = %{public}d", readBuf.tunProtocolInfo.flags);
260     }
261 
262     ClatdPacketConverter converter =
263         ClatdPacketConverter(readBuf.payload, packetLen, CONVERT_FROM_V4_TO_V6, v4Addr_, v6Addr_, prefixAddr_);
264     bool skip_csum = false;
265     if (converter.ConvertPacket(skip_csum) != NETMANAGER_SUCCESS) {
266         return;
267     }
268     std::vector<iovec> iovPackets(CLATD_MAX);
269     int effectivePos = 0;
270     converter.GetConvertedPacket(iovPackets, effectivePos);
271     if (effectivePos > 0) {
272         SendV6OnRawSocket(writeSock6_, iovPackets, effectivePos);
273     }
274 }
275 
ReadV6Packet(msghdr & msgHdr,ssize_t & readLen)276 int32_t Clatd::ReadV6Packet(msghdr &msgHdr, ssize_t &readLen)
277 {
278     readLen = recvmsg(readSock6_, &msgHdr, 0);
279     if (readLen < 0) {
280         if (errno != EAGAIN) {
281             NETNATIVE_LOGW("recvmsg failed: %{public}s", strerror(errno));
282         }
283         return NETMANAGER_ERR_OPERATION_FAILED;
284     } else if (readLen == 0) {
285         NETNATIVE_LOGW("recvmsg failed: socket closed");
286         isSocketClosed_ = true;
287         return NETMANAGER_ERR_OPERATION_FAILED;
288     } else if (static_cast<size_t>(readLen) >= sizeof(ClatdReadV6Buf)) {
289         NETNATIVE_LOGW("recvmsg failed: packet oversize, readLen: %{public}zu, sizeof(ClatdReadV6Buf): %{public}zu",
290                        static_cast<size_t>(readLen), sizeof(ClatdReadV6Buf));
291         return NETMANAGER_ERR_OPERATION_FAILED;
292     }
293     return NETMANAGER_SUCCESS;
294 }
295 
ReadV4Packet(ClatdReadTunBuf & readBuf,ssize_t & readLen)296 int32_t Clatd::ReadV4Packet(ClatdReadTunBuf &readBuf, ssize_t &readLen)
297 {
298     readLen = read(tunFd_, reinterpret_cast<iovec *>(&readBuf), sizeof(readBuf));
299     if (readLen < 0) {
300         NETNATIVE_LOGW("read failed: %{public}s", strerror(errno));
301         return NETMANAGER_ERR_OPERATION_FAILED;
302     } else if (readLen == 0) {
303         NETNATIVE_LOGW("read failed: socket closed");
304         isSocketClosed_ = true;
305         return NETMANAGER_ERR_OPERATION_FAILED;
306     } else if (static_cast<size_t>(readLen) >= sizeof(readBuf)) {
307         NETNATIVE_LOGW("read failed: packet oversize");
308         return NETMANAGER_ERR_OPERATION_FAILED;
309     }
310     return NETMANAGER_SUCCESS;
311 }
312 
SendV6OnRawSocket(int fd,std::vector<iovec> & iovPackets,int effectivePos)313 void Clatd::SendV6OnRawSocket(int fd, std::vector<iovec> &iovPackets, int effectivePos)
314 {
315     static sockaddr_in6 sin6 = {AF_INET6, 0, 0, {{{0, 0, 0, 0}}}, 0};
316     static msghdr msgHeader;
317     msgHeader.msg_name = &sin6;
318     msgHeader.msg_namelen = sizeof(sin6);
319 
320     msgHeader.msg_iov = &iovPackets[0];
321     msgHeader.msg_iovlen = effectivePos;
322     sin6.sin6_addr = reinterpret_cast<struct ip6_hdr *>(iovPackets[CLATD_TPHDR].iov_base)->ip6_dst;
323     sendmsg(fd, &msgHeader, 0);
324 }
325 
326 } // namespace nmd
327 } // namespace OHOS