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