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 #include "clatd_packet_converter.h"
16
17 #include <algorithm>
18 #include <climits>
19 #include <linux/if_tun.h>
20 #include <netinet/icmp6.h>
21 #include <netinet/in.h>
22 #include <netinet/ip.h>
23 #include <netinet/ip6.h>
24 #include <netinet/ip_icmp.h>
25 #include <netinet/tcp.h>
26 #include <netinet/udp.h>
27 #include <string>
28 #include <sys/uio.h>
29 #include <vector>
30
31 #include "clat_constants.h"
32 #include "clat_utils.h"
33 #include "net_manager_constants.h"
34 #include "netnative_log_wrapper.h"
35 #include "securec.h"
36
37 namespace OHOS {
38 namespace nmd {
39 using namespace OHOS::NetManagerStandard;
40
ClatdPacketConverter(const uint8_t *inputPacket, size_t inputPacketSize, ClatdConvertType convertType, const in_addr &v4Addr, const in6_addr &v6Addr, const in6_addr &prefixAddr)41 ClatdPacketConverter::ClatdPacketConverter(const uint8_t *inputPacket, size_t inputPacketSize,
42 ClatdConvertType convertType, const in_addr &v4Addr, const in6_addr &v6Addr,
43 const in6_addr &prefixAddr)
44 : inputPacket_(inputPacket),
45 inputPacketSize_(inputPacketSize),
46 convertType_(convertType),
47 localV4Addr_(v4Addr),
48 localV6Addr_(v6Addr),
49 prefixAddr_(prefixAddr),
50 iovBufs_(CLATD_MAX),
51 iovBufLens_(CLATD_MAX)
52 {
53 }
54
ConvertPacket(bool skip_csum)55 int32_t ClatdPacketConverter::ConvertPacket(bool skip_csum)
56 {
57 int32_t ret;
58 if (convertType_ == CONVERT_FROM_V4_TO_V6) {
59 ret = ConvertV4Packet(CLATD_IPHDR, inputPacket_, inputPacketSize_);
60 if (ret != NETMANAGER_SUCCESS) {
61 NETNATIVE_LOGW("fail to convert ipv4 packet");
62 }
63 } else if (convertType_ == CONVERT_FROM_V6_TO_V4) {
64 ret = ConvertV6Packet(CLATD_IPHDR, inputPacket_, inputPacketSize_);
65 if (ret != NETMANAGER_SUCCESS) {
66 NETNATIVE_LOGW("fail to convert ipv6 packet");
67 } else if (effectivePos_ > 0) {
68 WriteTunHeader(skip_csum);
69 }
70 } else {
71 NETNATIVE_LOGW("invalid convert type");
72 ret = NETMANAGER_ERR_INVALID_PARAMETER;
73 }
74 return ret;
75 }
76
GetConvertedPacket(std::vector<iovec> &iovPackets, int &effectivePos)77 void ClatdPacketConverter::GetConvertedPacket(std::vector<iovec> &iovPackets, int &effectivePos)
78 {
79 for (size_t i = CLATD_TUNHDR; i < CLATD_MAX; i++) {
80 iovPackets[i].iov_base = iovBufs_[i].data();
81 iovPackets[i].iov_len = iovBufLens_[i];
82 }
83 effectivePos = effectivePos_;
84 }
85
ConvertV4Packet(int pos, const uint8_t *inputPacket, size_t inputPacketSize)86 int32_t ClatdPacketConverter::ConvertV4Packet(int pos, const uint8_t *inputPacket, size_t inputPacketSize)
87 {
88 const iphdr *ipHeader = reinterpret_cast<const iphdr *>(inputPacket);
89 if (!IsV4PacketValid(ipHeader, inputPacketSize)) {
90 return NETMANAGER_ERR_INVALID_PARAMETER;
91 }
92
93 // details about how to convert ip/icmp in RFC 6145
94 uint8_t v4TpProtocol = ipHeader->protocol;
95 uint8_t v6TpProtocol = v4TpProtocol;
96 if (v4TpProtocol == IPPROTO_ICMP) {
97 v6TpProtocol = IPPROTO_ICMPV6;
98 }
99
100 ip6_hdr ip6Header;
101 WriteIpv6Header(&ip6Header, v6TpProtocol, ipHeader);
102 iovBufLens_[pos] = sizeof(ip6_hdr);
103
104 ip6_frag ip6FragHeader;
105 size_t ip6FragHeaderLen = WriteFragHeader(&ip6FragHeader, &ip6Header, ipHeader);
106 iovBufLens_[pos + 1] = ip6FragHeaderLen;
107 iovBufs_[pos + 1].assign(reinterpret_cast<const char *>(&ip6FragHeader), iovBufLens_[pos + 1]);
108
109 size_t tpLen = inputPacketSize - ipHeader->ihl * WORD_32BIT_IN_BYTE_UNIT;
110 const uint8_t *tpHeader = inputPacket + ipHeader->ihl * WORD_32BIT_IN_BYTE_UNIT;
111 if (ip6FragHeaderLen > 0 && (ip6FragHeader.ip6f_offlg & IP6F_OFF_MASK)) {
112 WritePayload(pos, tpHeader, tpLen);
113 ip6Header.ip6_plen = htons(GetIovPacketLength(pos));
114 iovBufs_[pos].assign(reinterpret_cast<const char *>(&ip6Header), iovBufLens_[pos]);
115 return NETMANAGER_SUCCESS;
116 }
117 return ConvertV4TpPacket(pos, ipHeader, &ip6Header, tpLen, v6TpProtocol);
118 }
119
ConvertV4TpPacket(int pos, const iphdr *ipHeader, ip6_hdr *ip6Header, size_t tpLen, uint8_t v6TpProtocol)120 int32_t ClatdPacketConverter::ConvertV4TpPacket(int pos, const iphdr *ipHeader, ip6_hdr *ip6Header, size_t tpLen,
121 uint8_t v6TpProtocol)
122 {
123 uint8_t v4TpProtocol = ipHeader->protocol;
124 uint32_t oldChecksum = CalV4PseudoHeaderChecksum(ipHeader, tpLen, v4TpProtocol);
125 uint32_t newChecksum = CalV6PseudoHeaderChecksum(ip6Header, tpLen, v6TpProtocol);
126 const uint8_t *tpHeader = reinterpret_cast<const uint8_t *>(ipHeader) + ipHeader->ihl * WORD_32BIT_IN_BYTE_UNIT;
127 int32_t ret;
128 switch (v6TpProtocol) {
129 case IPPROTO_ICMPV6:
130 ret = ConvertIcmpPacket(pos + IP_TP_PACKET_POSITION_DELTA, reinterpret_cast<const icmphdr *>(tpHeader),
131 newChecksum, tpLen);
132 break;
133 case IPPROTO_TCP:
134 ret = ConvertTcpPacket(pos + IP_TP_PACKET_POSITION_DELTA, reinterpret_cast<const tcphdr *>(tpHeader),
135 oldChecksum, newChecksum, tpLen);
136 break;
137 case IPPROTO_UDP:
138 ret = ConvertUdpPacket(pos + IP_TP_PACKET_POSITION_DELTA, reinterpret_cast<const udphdr *>(tpHeader),
139 oldChecksum, newChecksum, tpLen);
140 break;
141 case IPPROTO_GRE:
142 case IPPROTO_ESP:
143 WritePayload(pos, tpHeader, tpLen);
144 ret = NETMANAGER_SUCCESS;
145 break;
146 default:
147 NETNATIVE_LOGW("unknown transport protocol");
148 ret = NETMANAGER_ERR_INVALID_PARAMETER;
149 }
150 ip6Header->ip6_plen = htons(GetIovPacketLength(pos));
151 iovBufs_[pos].assign(reinterpret_cast<const char *>(ip6Header), iovBufLens_[pos]);
152 return ret;
153 }
154
ConvertV6Packet(int pos, const uint8_t *inputPacket, size_t inputPacketSize)155 int32_t ClatdPacketConverter::ConvertV6Packet(int pos, const uint8_t *inputPacket, size_t inputPacketSize)
156 {
157 const ip6_hdr *ip6Header = reinterpret_cast<const ip6_hdr *>(inputPacket);
158 if (!IsV6PacketValid(ip6Header, inputPacketSize)) {
159 return NETMANAGER_ERR_INVALID_PARAMETER;
160 }
161
162 // details about how to convert ip/icmp in RFC 6145
163 uint8_t v6TpProtocol = ip6Header->ip6_nxt;
164 uint8_t v4TpProtocol = v6TpProtocol == IPPROTO_ICMPV6 ? IPPROTO_ICMP : v6TpProtocol;
165
166 iphdr ipHeader;
167 WriteIpv4Header(&ipHeader, v4TpProtocol, ip6Header);
168 iovBufLens_[pos] = sizeof(iphdr);
169
170 size_t tpLen = inputPacketSize - sizeof(ip6_hdr);
171 const uint8_t *tpHeader = inputPacket + sizeof(ip6_hdr);
172
173 const ip6_frag *ip6FragHeader = nullptr;
174 if (v6TpProtocol == IPPROTO_FRAGMENT) {
175 ip6FragHeader = reinterpret_cast<const ip6_frag *>(tpHeader);
176 // LCOV_EXCL_START
177 if (tpLen < sizeof(*ip6FragHeader)) {
178 NETNATIVE_LOGW("fail to convert ipv6 packet, fragment packet size is too small");
179 effectivePos_ = 0;
180 return NETMANAGER_ERR_INVALID_PARAMETER;
181 }
182 // LCOV_EXCL_STOP
183 tpHeader += sizeof(*ip6FragHeader);
184 tpLen -= sizeof(*ip6FragHeader);
185
186 ProcessFragHeader(ip6FragHeader, &ipHeader, v6TpProtocol, v4TpProtocol);
187 }
188
189 if (ip6FragHeader != nullptr && (ip6FragHeader->ip6f_offlg & IP6F_OFF_MASK)) {
190 WritePayload(pos, tpHeader, tpLen);
191 ipHeader.tot_len = htons(ntohs(ipHeader.tot_len) + GetIovPacketLength(pos));
192 ipHeader.check = CalChecksum(&ipHeader, sizeof(iphdr));
193 iovBufs_[pos].assign(reinterpret_cast<const char *>(&ipHeader), iovBufLens_[pos]);
194 return NETMANAGER_SUCCESS;
195 }
196
197 return ConvertV6TpPacket(pos, ip6Header, &ipHeader, tpLen, v4TpProtocol);
198 }
199
ConvertV6TpPacket(int pos, const ip6_hdr *ip6Header, iphdr *ipHeader, size_t tpLen, uint8_t v4TpProtocol)200 int32_t ClatdPacketConverter::ConvertV6TpPacket(int pos, const ip6_hdr *ip6Header, iphdr *ipHeader, size_t tpLen,
201 uint8_t v4TpProtocol)
202 {
203 uint8_t v6TpProtocol = ip6Header->ip6_nxt;
204 uint32_t oldChecksum = CalV6PseudoHeaderChecksum(ip6Header, tpLen, v6TpProtocol);
205 uint32_t newChecksum = CalV4PseudoHeaderChecksum(ipHeader, tpLen, v4TpProtocol);
206 const uint8_t *tpHeader = reinterpret_cast<const uint8_t *>(ip6Header) + sizeof(ip6_hdr);
207 int32_t ret;
208 switch (v4TpProtocol) {
209 case IPPROTO_ICMP:
210 ret = ConvertIcmpv6Packet(pos + IP_TP_PACKET_POSITION_DELTA, reinterpret_cast<const icmp6_hdr *>(tpHeader),
211 tpLen);
212 break;
213 case IPPROTO_TCP:
214 ret = ConvertTcpPacket(pos + IP_TP_PACKET_POSITION_DELTA, reinterpret_cast<const tcphdr *>(tpHeader),
215 oldChecksum, newChecksum, tpLen);
216 break;
217 case IPPROTO_UDP:
218 ret = ConvertUdpPacket(pos + IP_TP_PACKET_POSITION_DELTA, reinterpret_cast<const udphdr *>(tpHeader),
219 oldChecksum, newChecksum, tpLen);
220 break;
221 case IPPROTO_GRE:
222 case IPPROTO_ESP:
223 WritePayload(pos, tpHeader, tpLen);
224 ret = NETMANAGER_SUCCESS;
225 break;
226 default:
227 NETNATIVE_LOGW("unknown transport protocol");
228 ret = NETMANAGER_ERR_INVALID_PARAMETER;
229 }
230 ipHeader->tot_len = htons(ntohs(ipHeader->tot_len) + GetIovPacketLength(pos));
231 ipHeader->check = CalChecksum(ipHeader, sizeof(iphdr));
232 iovBufs_[pos].assign(reinterpret_cast<const char *>(ipHeader), iovBufLens_[pos]);
233 return ret;
234 }
235
IsV4PacketValid(const iphdr *ipHeader, size_t packetSize)236 bool ClatdPacketConverter::IsV4PacketValid(const iphdr *ipHeader, size_t packetSize)
237 {
238 if (packetSize < sizeof(iphdr)) {
239 NETNATIVE_LOGW("Invalid ipv4 packet, input packet size too small");
240 return false;
241 }
242 if (ipHeader->ihl * WORD_32BIT_IN_BYTE_UNIT < IPV4_HDR_MIN_LEN) {
243 NETNATIVE_LOGW("Invalid ipv4 packet, ip header length %{public}u smaller than 5", ipHeader->ihl);
244 return false;
245 }
246 if (static_cast<size_t>(ipHeader->ihl * WORD_32BIT_IN_BYTE_UNIT) > packetSize) {
247 NETNATIVE_LOGW("Invalid ipv4 packet, ip header length %{public}u larger than entire packet", ipHeader->ihl);
248 return false;
249 }
250 if (ipHeader->version != IPVERSION) {
251 NETNATIVE_LOGW("Invalid ipv4 packet, version %{public}u not 4", ipHeader->version);
252 return false;
253 }
254 return true;
255 }
256
IsV6PacketValid(const ip6_hdr *ip6Header, size_t packetSize)257 bool ClatdPacketConverter::IsV6PacketValid(const ip6_hdr *ip6Header, size_t packetSize)
258 {
259 if (packetSize < sizeof(ip6_hdr)) {
260 NETNATIVE_LOGW("Invalid ipv6 packet, input packet size too small");
261 return false;
262 }
263
264 if (IN6_IS_ADDR_MULTICAST(&ip6Header->ip6_dst)) {
265 NETNATIVE_LOGW("Invalid ipv6 packet, destination address is multicast");
266 return false;
267 }
268
269 if (!(std::equal(prefixAddr_.s6_addr, prefixAddr_.s6_addr + CLAT_PREFIX_BYTE_LEN, ip6Header->ip6_src.s6_addr) &&
270 IN6_ARE_ADDR_EQUAL(&ip6Header->ip6_dst, &localV6Addr_)) &&
271 !(std::equal(prefixAddr_.s6_addr, prefixAddr_.s6_addr + CLAT_PREFIX_BYTE_LEN, ip6Header->ip6_dst.s6_addr) &&
272 IN6_ARE_ADDR_EQUAL(&ip6Header->ip6_src, &localV6Addr_)) &&
273 ip6Header->ip6_nxt != IPPROTO_ICMPV6) {
274 NETNATIVE_LOGW("Invalid ipv6 packet, unknown source/destination address");
275 return false;
276 }
277
278 return true;
279 }
280
WriteIpv6Header(ip6_hdr *ip6Header, uint8_t tpProtocol, const iphdr *ipHeader)281 void ClatdPacketConverter::WriteIpv6Header(ip6_hdr *ip6Header, uint8_t tpProtocol, const iphdr *ipHeader)
282 {
283 ip6Header->ip6_vfc = IPV6_VERSION_FLAG;
284 ip6Header->ip6_plen = 0;
285 ip6Header->ip6_nxt = tpProtocol;
286 ip6Header->ip6_hlim = ipHeader->ttl;
287
288 ConvertV4Address(ipHeader->saddr, ip6Header->ip6_src);
289 ConvertV4Address(ipHeader->daddr, ip6Header->ip6_dst);
290 }
291
WriteIpv4Header(iphdr *ipHeader, uint8_t tpProtocol, const ip6_hdr *ip6Header)292 void ClatdPacketConverter::WriteIpv4Header(iphdr *ipHeader, uint8_t tpProtocol, const ip6_hdr *ip6Header)
293 {
294 ipHeader->ihl = (IPV4_HDR_MIN_LEN / WORD_32BIT_IN_BYTE_UNIT);
295 ipHeader->version = IPVERSION;
296 ipHeader->tos = 0;
297 ipHeader->tot_len = htons(sizeof(iphdr));
298 ipHeader->id = 0;
299 ipHeader->frag_off = htons(IP_DF);
300 ipHeader->ttl = ip6Header->ip6_hlim;
301 ipHeader->protocol = tpProtocol;
302 ipHeader->check = 0;
303
304 ConvertV6Address(ip6Header->ip6_src, ipHeader->saddr);
305 ConvertV6Address(ip6Header->ip6_dst, ipHeader->daddr);
306
307 if (static_cast<uint32_t>(ipHeader->saddr) == INADDR_NONE) {
308 ipHeader->saddr = htonl((0xffffff << CHAR_BIT) + ip6Header->ip6_hlim);
309 }
310 }
311
ConvertV4Address(uint32_t v4Addr, in6_addr &v6Addr)312 void ClatdPacketConverter::ConvertV4Address(uint32_t v4Addr, in6_addr &v6Addr)
313 {
314 if (v4Addr == localV4Addr_.s_addr) {
315 v6Addr = localV6Addr_;
316 } else {
317 v6Addr = prefixAddr_;
318 v6Addr.s6_addr32[CLAT_SUFFIX_OFFSET_IN_32] = v4Addr;
319 }
320 }
321
ConvertV6Address(const in6_addr &v6Addr, uint32_t &v4Addr)322 void ClatdPacketConverter::ConvertV6Address(const in6_addr &v6Addr, uint32_t &v4Addr)
323 {
324 if (std::equal(prefixAddr_.s6_addr, prefixAddr_.s6_addr + CLAT_PREFIX_BYTE_LEN, v6Addr.s6_addr)) {
325 v4Addr = v6Addr.s6_addr32[CLAT_SUFFIX_OFFSET_IN_32];
326 } else if (IN6_ARE_ADDR_EQUAL(&v6Addr, &localV6Addr_)) {
327 v4Addr = localV4Addr_.s_addr;
328 } else {
329 v4Addr = INADDR_NONE;
330 }
331 }
332
WriteFragHeader(ip6_frag *ip6FragHeader, ip6_hdr *ip6Header, const iphdr *ipHeader)333 size_t ClatdPacketConverter::WriteFragHeader(ip6_frag *ip6FragHeader, ip6_hdr *ip6Header, const iphdr *ipHeader)
334 {
335 uint16_t fragValue = ntohs(ipHeader->frag_off);
336 uint16_t fragOffset = fragValue & IP_OFFMASK;
337 if (fragOffset == 0 && (fragValue & IP_MF) == 0) {
338 return 0;
339 }
340
341 ip6FragHeader->ip6f_nxt = ip6Header->ip6_nxt;
342 ip6FragHeader->ip6f_reserved = 0;
343 ip6FragHeader->ip6f_offlg = htons(fragOffset << IPV6_FRAG_OFFSET_BIT_SUPPLEMENTARY);
344 if (fragValue & IP_MF) {
345 ip6FragHeader->ip6f_offlg |= IP6F_MORE_FRAG;
346 }
347 ip6FragHeader->ip6f_ident = htonl(ntohs(ipHeader->id));
348 ip6Header->ip6_nxt = IPPROTO_FRAGMENT;
349
350 return sizeof(*ip6FragHeader);
351 }
352
ProcessFragHeader(const ip6_frag *ip6FragHeader, iphdr *ipHeader, uint8_t &v6TpProtocol, uint8_t &v4TpProtocol)353 void ClatdPacketConverter::ProcessFragHeader(const ip6_frag *ip6FragHeader, iphdr *ipHeader, uint8_t &v6TpProtocol,
354 uint8_t &v4TpProtocol)
355 {
356 uint16_t fragOffset = ntohs(ip6FragHeader->ip6f_offlg & IP6F_OFF_MASK) >> IPV6_FRAG_OFFSET_BIT_SUPPLEMENTARY;
357 if (ip6FragHeader->ip6f_offlg & IP6F_MORE_FRAG) {
358 fragOffset |= IP_MF;
359 }
360 ipHeader->frag_off = htons(fragOffset);
361 ipHeader->id = htons(ntohl(ip6FragHeader->ip6f_ident) & 0xffff);
362
363 v6TpProtocol = ip6FragHeader->ip6f_nxt;
364 v4TpProtocol = v6TpProtocol == IPPROTO_ICMPV6 ? IPPROTO_ICMP : v6TpProtocol;
365 ipHeader->protocol = v4TpProtocol;
366 }
367
CalV4PseudoHeaderChecksum(const iphdr *ipHeader, uint16_t tpLen, uint8_t tpProtocol)368 uint32_t ClatdPacketConverter::CalV4PseudoHeaderChecksum(const iphdr *ipHeader, uint16_t tpLen, uint8_t tpProtocol)
369 {
370 uint16_t len = htons(tpLen);
371 uint16_t protocol = htons(tpProtocol);
372 uint32_t sum = 0;
373
374 sum = AddChecksum(sum, &(ipHeader->saddr), sizeof(uint32_t));
375 sum = AddChecksum(sum, &(ipHeader->daddr), sizeof(uint32_t));
376 sum = AddChecksum(sum, &len, sizeof(uint16_t));
377 sum = AddChecksum(sum, &protocol, sizeof(uint16_t));
378 return sum;
379 }
380
CalV6PseudoHeaderChecksum(const ip6_hdr *ip6Header, uint32_t tpLen, uint8_t tpProtocol)381 uint32_t ClatdPacketConverter::CalV6PseudoHeaderChecksum(const ip6_hdr *ip6Header, uint32_t tpLen, uint8_t tpProtocol)
382 {
383 uint32_t len = htonl(tpLen);
384 uint32_t protocol = htonl(tpProtocol);
385 uint32_t sum = 0;
386
387 sum = AddChecksum(sum, &(ip6Header->ip6_src), sizeof(in6_addr));
388 sum = AddChecksum(sum, &(ip6Header->ip6_dst), sizeof(in6_addr));
389 sum = AddChecksum(sum, &len, sizeof(uint32_t));
390 sum = AddChecksum(sum, &protocol, sizeof(uint32_t));
391 return sum;
392 }
393
GetIovPacketLength(int pos)394 uint16_t ClatdPacketConverter::GetIovPacketLength(int pos)
395 {
396 size_t sum = 0;
397 for (size_t i = pos + 1; i < static_cast<int>(CLATD_MAX); i++) {
398 sum += iovBufLens_[i];
399 }
400 return sum;
401 }
402
ConvertIcmpPacket(int pos, const icmphdr *icmpHeader, uint32_t checksum, size_t tpLen)403 int32_t ClatdPacketConverter::ConvertIcmpPacket(int pos, const icmphdr *icmpHeader, uint32_t checksum, size_t tpLen)
404 {
405 if (tpLen < sizeof(icmphdr)) {
406 NETNATIVE_LOGW("fail to convert icmp packet, packet length is too small");
407 effectivePos_ = 0;
408 return NETMANAGER_ERR_INVALID_PARAMETER;
409 }
410
411 icmp6_hdr icmp6Header;
412
413 ConvertIcmpTypeAndCode(icmpHeader->type, icmpHeader->code, icmp6Header.icmp6_type, icmp6Header.icmp6_code);
414
415 iovBufLens_[pos] = sizeof(icmp6_hdr);
416
417 const uint8_t *payload = reinterpret_cast<const uint8_t *>(icmpHeader + 1);
418 size_t payloadLen = tpLen - sizeof(icmphdr);
419
420 int32_t ret;
421 if (pos == static_cast<int>(CLATD_TPHDR) &&
422 (icmp6Header.icmp6_type == ICMP6_DST_UNREACH || icmp6Header.icmp6_type == ICMP6_TIME_EXCEEDED)) {
423 ret = ConvertV4Packet(pos + 1, payload, payloadLen);
424
425 checksum = checksum + htons(IPV6_HDR_LEN - IPV4_HDR_MIN_LEN);
426 } else if (icmp6Header.icmp6_type == ICMP6_ECHO_REQUEST || icmp6Header.icmp6_type == ICMP6_ECHO_REPLY) {
427 // Ping packet.
428 icmp6Header.icmp6_id = icmpHeader->un.echo.id;
429 icmp6Header.icmp6_seq = icmpHeader->un.echo.sequence;
430 iovBufs_[CLATD_PAYLOAD].assign(reinterpret_cast<const char *>(payload), payloadLen);
431 iovBufLens_[CLATD_PAYLOAD] = payloadLen;
432 effectivePos_ = CLATD_PAYLOAD + 1;
433 ret = NETMANAGER_SUCCESS;
434 } else {
435 effectivePos_ = 0;
436 ret = NETMANAGER_ERR_INVALID_PARAMETER;
437 }
438
439 icmp6Header.icmp6_cksum = 0;
440 iovBufs_[pos].assign(reinterpret_cast<const char *>(&icmp6Header), iovBufLens_[pos]);
441 icmp6Header.icmp6_cksum = CalIovPacketChecksum(checksum, pos);
442 iovBufs_[pos].assign(reinterpret_cast<const char *>(&icmp6Header), iovBufLens_[pos]);
443 return ret;
444 }
445
ConvertIcmpTypeAndCode(const uint8_t &icmpType, const uint8_t &icmpCode, uint8_t &icmp6Type, uint8_t &icmp6Code)446 void ClatdPacketConverter::ConvertIcmpTypeAndCode(const uint8_t &icmpType, const uint8_t &icmpCode, uint8_t &icmp6Type,
447 uint8_t &icmp6Code)
448 {
449 switch (icmpType) {
450 case ICMP_ECHO:
451 icmp6Type = ICMP6_ECHO_REQUEST;
452 icmp6Code = icmpCode;
453 break;
454 case ICMP_ECHOREPLY:
455 icmp6Type = ICMP6_ECHO_REPLY;
456 icmp6Code = icmpCode;
457 break;
458 case ICMP_TIME_EXCEEDED:
459 icmp6Type = ICMP6_TIME_EXCEEDED;
460 icmp6Code = icmpCode;
461 break;
462 case ICMP_DEST_UNREACH:
463 switch (icmpCode) {
464 case ICMP_UNREACH_NET:
465 case ICMP_UNREACH_HOST:
466 case ICMP_UNREACH_SRCFAIL:
467 case ICMP_UNREACH_NET_UNKNOWN:
468 case ICMP_UNREACH_HOST_UNKNOWN:
469 case ICMP_UNREACH_ISOLATED:
470 case ICMP_UNREACH_TOSNET:
471 case ICMP_UNREACH_TOSHOST:
472 icmp6Type = ICMP6_DST_UNREACH;
473 icmp6Code = ICMP6_DST_UNREACH_NOROUTE;
474 break;
475 case ICMP_UNREACH_PORT:
476 icmp6Type = ICMP6_DST_UNREACH;
477 icmp6Code = ICMP6_DST_UNREACH_NOPORT;
478 break;
479 case ICMP_UNREACH_NET_PROHIB:
480 case ICMP_UNREACH_HOST_PROHIB:
481 case ICMP_UNREACH_FILTER_PROHIB:
482 case ICMP_UNREACH_PRECEDENCE_CUTOFF:
483 icmp6Type = ICMP6_DST_UNREACH;
484 icmp6Code = ICMP6_DST_UNREACH_ADMIN;
485 break;
486 default:
487 icmp6Type = ICMP6_PARAM_PROB;
488 NETNATIVE_LOGW("fail to convert icmp packet type %{public}d code %{public}d", icmpType, icmpCode);
489 break;
490 }
491 break;
492 default:
493 NETNATIVE_LOGW("fail to convert icmp packet type %{public}d", icmpType);
494 icmp6Type = ICMP6_PARAM_PROB;
495 }
496 }
497
ConvertIcmpv6Packet(int pos, const icmp6_hdr *icmp6Header, size_t tpLen)498 int32_t ClatdPacketConverter::ConvertIcmpv6Packet(int pos, const icmp6_hdr *icmp6Header, size_t tpLen)
499 {
500 if (tpLen < sizeof(icmp6_hdr)) {
501 NETNATIVE_LOGW("fail to convert icmp6 packet, packet length is too small");
502 effectivePos_ = 0;
503 return NETMANAGER_ERR_INVALID_PARAMETER;
504 }
505
506 icmphdr icmpHeader;
507 ConvertIcmpV6TypeAndCode(icmp6Header->icmp6_type, icmp6Header->icmp6_code, icmpHeader.type, icmpHeader.code);
508 iovBufLens_[pos] = sizeof(icmphdr);
509
510 const uint8_t *payload = reinterpret_cast<const uint8_t *>(icmp6Header + 1);
511 size_t payloadLen = tpLen - sizeof(icmp6_hdr);
512 int32_t ret;
513 if (pos == CLATD_TPHDR && icmp6Header->icmp6_type < ICMP6_ECHO_REQUEST && icmpHeader.type != ICMP_PARAMETERPROB) {
514 ret = ConvertV6Packet(pos + 1, payload, payloadLen);
515 } else if (icmpHeader.type == ICMP_ECHO || icmpHeader.type == ICMP_ECHOREPLY) {
516 // Ping packet.
517 icmpHeader.un.echo.id = icmp6Header->icmp6_id;
518 icmpHeader.un.echo.sequence = icmp6Header->icmp6_seq;
519 iovBufs_[CLATD_PAYLOAD].assign(reinterpret_cast<const char *>(payload), payloadLen);
520 iovBufLens_[CLATD_PAYLOAD] = payloadLen;
521 effectivePos_ = CLATD_PAYLOAD + 1;
522 ret = NETMANAGER_SUCCESS;
523 } else {
524 effectivePos_ = 0;
525 ret = NETMANAGER_ERR_INVALID_PARAMETER;
526 }
527
528 icmpHeader.checksum = 0;
529 iovBufs_[pos].assign(reinterpret_cast<const char *>(&icmpHeader), iovBufLens_[pos]);
530 icmpHeader.checksum = CalIovPacketChecksum(0, pos);
531 iovBufs_[pos].assign(reinterpret_cast<const char *>(&icmpHeader), iovBufLens_[pos]);
532
533 return ret;
534 }
535
ConvertIcmpV6TypeAndCode(const uint8_t &icmp6Type, const uint8_t &icmp6Code, uint8_t &icmpType, uint8_t &icmpCode)536 void ClatdPacketConverter::ConvertIcmpV6TypeAndCode(const uint8_t &icmp6Type, const uint8_t &icmp6Code,
537 uint8_t &icmpType, uint8_t &icmpCode)
538 {
539 switch (icmp6Type) {
540 case ICMP6_ECHO_REQUEST:
541 icmpType = ICMP_ECHO;
542 icmpCode = icmp6Code;
543 break;
544 case ICMP6_ECHO_REPLY:
545 icmpType = ICMP_ECHOREPLY;
546 icmpCode = icmp6Code;
547 break;
548 case ICMP6_TIME_EXCEEDED:
549 icmpType = ICMP_TIME_EXCEEDED;
550 icmpCode = icmp6Code;
551 break;
552 case ICMP6_DST_UNREACH:
553 switch (icmp6Code) {
554 case ICMP6_DST_UNREACH_NOROUTE:
555 case ICMP6_DST_UNREACH_BEYONDSCOPE:
556 case ICMP6_DST_UNREACH_ADDR:
557 icmpType = ICMP_DEST_UNREACH;
558 icmpCode = ICMP_UNREACH_HOST;
559 break;
560
561 case ICMP6_DST_UNREACH_ADMIN:
562 icmpType = ICMP_DEST_UNREACH;
563 icmpCode = ICMP_UNREACH_HOST_PROHIB;
564 break;
565
566 case ICMP6_DST_UNREACH_NOPORT:
567 icmpType = ICMP_DEST_UNREACH;
568 icmpCode = ICMP_UNREACH_PORT;
569 break;
570 default:
571 NETNATIVE_LOGW("fail to convert icmpv6 packet type %{public}d", icmp6Type);
572 icmpType = ICMP_PARAMETERPROB;
573 }
574 break;
575 default:
576 NETNATIVE_LOGW("fail to convert icmpv6 packet type %{public}d", icmp6Type);
577 icmpType = ICMP_PARAMETERPROB;
578 }
579 }
580
CalIovPacketChecksum(uint32_t sum, int pos)581 uint16_t ClatdPacketConverter::CalIovPacketChecksum(uint32_t sum, int pos)
582 {
583 for (size_t i = pos; i < CLATD_MAX; i++) {
584 if (iovBufLens_[i] > 0) {
585 sum = AddChecksum(sum, iovBufs_[i].data(), iovBufLens_[i]);
586 }
587 }
588 return ~Checksum32To16(sum);
589 }
590
ConvertTcpPacket(int pos, const tcphdr *tcpHeader, uint32_t oldChecksum, uint32_t newChecksum, size_t tpLen)591 int32_t ClatdPacketConverter::ConvertTcpPacket(int pos, const tcphdr *tcpHeader, uint32_t oldChecksum,
592 uint32_t newChecksum, size_t tpLen)
593 {
594 if (!IsTcpPacketValid(tcpHeader, tpLen)) {
595 return NETMANAGER_ERR_INVALID_PARAMETER;
596 }
597
598 size_t tcpHdrLen = tcpHeader->doff * WORD_32BIT_IN_BYTE_UNIT;
599 iovBufLens_[pos] = tcpHdrLen;
600
601 char tcpHdrBuf[TCP_HDR_MAX_LEN];
602 // LCOV_EXCL_START
603 if (memcpy_s(tcpHdrBuf, TCP_HDR_MAX_LEN, tcpHeader, tcpHdrLen) != EOK) {
604 return NETMANAGER_ERR_OPERATION_FAILED;
605 }
606 // LCOV_EXCL_STOP
607 tcphdr *tcpHeaderOut = reinterpret_cast<tcphdr *>(tcpHdrBuf);
608
609 iovBufs_[CLATD_PAYLOAD].assign(reinterpret_cast<const char *>(tcpHeader) + tcpHdrLen, tpLen - tcpHdrLen);
610 iovBufLens_[CLATD_PAYLOAD] = tpLen - tcpHdrLen;
611 tcpHeaderOut->check = AdjustChecksum(tcpHeader->check, oldChecksum, newChecksum);
612 iovBufs_[pos].assign(reinterpret_cast<const char *>(tcpHdrBuf), tcpHdrLen);
613 effectivePos_ = CLATD_PAYLOAD + 1;
614 return NETMANAGER_SUCCESS;
615 }
616
IsTcpPacketValid(const tcphdr *tcpHeader, size_t packetSize)617 bool ClatdPacketConverter::IsTcpPacketValid(const tcphdr *tcpHeader, size_t packetSize)
618 {
619 if (packetSize < sizeof(tcphdr)) {
620 NETNATIVE_LOGW("Invalid tcp packet, packet length is too small");
621 effectivePos_ = 0;
622 return false;
623 }
624
625 if (tcpHeader->doff * WORD_32BIT_IN_BYTE_UNIT < TCP_HDR_MIN_LEN) {
626 NETNATIVE_LOGW("Invalid tcp packet, tcp header length %{public}u smaller than 5", tcpHeader->doff);
627 effectivePos_ = 0;
628 return false;
629 }
630
631 if (static_cast<size_t>(tcpHeader->doff * WORD_32BIT_IN_BYTE_UNIT) > packetSize) {
632 NETNATIVE_LOGW("Invalid tcp packet, tcp header length %{public}u larger than entire packet", tcpHeader->doff);
633 effectivePos_ = 0;
634 return false;
635 }
636 // LCOV_EXCL_START
637 if (tcpHeader->doff * WORD_32BIT_IN_BYTE_UNIT > TCP_HDR_MAX_LEN) {
638 NETNATIVE_LOGW("Invalid tcp packet, tcp header length %{public}u larger than MAX_TCP_HDR", tcpHeader->doff);
639 effectivePos_ = 0;
640 return false;
641 }
642 // LCOV_EXCL_STOP
643 return true;
644 }
645
ConvertUdpPacket(int pos, const udphdr *udpHeader, uint32_t oldChecksum, uint32_t newChecksum, size_t tpLen)646 int32_t ClatdPacketConverter::ConvertUdpPacket(int pos, const udphdr *udpHeader, uint32_t oldChecksum,
647 uint32_t newChecksum, size_t tpLen)
648 {
649 if (tpLen < sizeof(udphdr)) {
650 NETNATIVE_LOGW("Invalid udp packet, packet length is too small");
651 effectivePos_ = 0;
652 return NETMANAGER_ERR_INVALID_PARAMETER;
653 }
654
655 iovBufLens_[pos] = sizeof(udphdr);
656
657 iovBufLens_[CLATD_PAYLOAD] = tpLen - sizeof(udphdr);
658 iovBufs_[CLATD_PAYLOAD].assign(reinterpret_cast<const char *>(udpHeader + 1), tpLen - sizeof(udphdr));
659
660 udphdr udpHeaderOut = *udpHeader;
661 // details about zero checksum in RFC 768
662 if (udpHeaderOut.check == 0) {
663 iovBufs_[pos].assign(reinterpret_cast<const char *>(&udpHeaderOut), sizeof(udphdr));
664 udpHeaderOut.check = CalIovPacketChecksum(newChecksum, pos);
665 } else {
666 udpHeaderOut.check = AdjustChecksum(udpHeader->check, oldChecksum, newChecksum);
667 }
668
669 // LCOV_EXCL_START
670 if (udpHeaderOut.check == 0) {
671 udpHeaderOut.check = 0xffff;
672 }
673 // LCOV_EXCL_STOP
674 iovBufs_[pos].assign(reinterpret_cast<const char *>(&udpHeaderOut), sizeof(udphdr));
675 effectivePos_ = CLATD_PAYLOAD + 1;
676 return NETMANAGER_SUCCESS;
677 }
678
WritePayload(int pos, const uint8_t *tpHeader, size_t tpLen)679 void ClatdPacketConverter::WritePayload(int pos, const uint8_t *tpHeader, size_t tpLen)
680 {
681 iovBufLens_[pos + IP_TP_PACKET_POSITION_DELTA] = 0;
682 iovBufs_[CLATD_PAYLOAD].assign(reinterpret_cast<const char *>(tpHeader), tpLen);
683 iovBufLens_[CLATD_PAYLOAD] = tpLen;
684 effectivePos_ = CLATD_MAX;
685 }
686
WriteTunHeader(bool skip_csum)687 void ClatdPacketConverter::WriteTunHeader(bool skip_csum)
688 {
689 tun_pi tunProtocolInfo;
690 if (skip_csum) {
691 tunProtocolInfo.flags = htons(TP_CSUM_UNNECESSARY);
692 } else {
693 tunProtocolInfo.flags = 0;
694 }
695 tunProtocolInfo.proto = htons(ETH_P_IP);
696 iovBufLens_[CLATD_TUNHDR] = sizeof(tun_pi);
697 iovBufs_[CLATD_TUNHDR].assign(reinterpret_cast<const char *>(&tunProtocolInfo), sizeof(tun_pi));
698 }
699
700 } // namespace nmd
701 } // namespace OHOS