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 if (tpLen < sizeof(*ip6FragHeader)) {
177 NETNATIVE_LOGW("fail to convert ipv6 packet, fragment packet size is too small");
178 effectivePos_ = 0;
179 return NETMANAGER_ERR_INVALID_PARAMETER;
180 }
181 tpHeader += sizeof(*ip6FragHeader);
182 tpLen -= sizeof(*ip6FragHeader);
183
184 ProcessFragHeader(ip6FragHeader, &ipHeader, v6TpProtocol, v4TpProtocol);
185 }
186
187 if (ip6FragHeader != nullptr && (ip6FragHeader->ip6f_offlg & IP6F_OFF_MASK)) {
188 WritePayload(pos, tpHeader, tpLen);
189 ipHeader.tot_len = htons(ntohs(ipHeader.tot_len) + GetIovPacketLength(pos));
190 ipHeader.check = CalChecksum(&ipHeader, sizeof(iphdr));
191 iovBufs_[pos].assign(reinterpret_cast<const char *>(&ipHeader), iovBufLens_[pos]);
192 return NETMANAGER_SUCCESS;
193 }
194
195 return ConvertV6TpPacket(pos, ip6Header, &ipHeader, tpLen, v4TpProtocol);
196 }
197
ConvertV6TpPacket(int pos,const ip6_hdr * ip6Header,iphdr * ipHeader,size_t tpLen,uint8_t v4TpProtocol)198 int32_t ClatdPacketConverter::ConvertV6TpPacket(int pos, const ip6_hdr *ip6Header, iphdr *ipHeader, size_t tpLen,
199 uint8_t v4TpProtocol)
200 {
201 uint8_t v6TpProtocol = ip6Header->ip6_nxt;
202 uint32_t oldChecksum = CalV6PseudoHeaderChecksum(ip6Header, tpLen, v6TpProtocol);
203 uint32_t newChecksum = CalV4PseudoHeaderChecksum(ipHeader, tpLen, v4TpProtocol);
204 const uint8_t *tpHeader = reinterpret_cast<const uint8_t *>(ip6Header) + sizeof(ip6_hdr);
205 int32_t ret;
206 switch (v4TpProtocol) {
207 case IPPROTO_ICMP:
208 ret = ConvertIcmpv6Packet(pos + IP_TP_PACKET_POSITION_DELTA, reinterpret_cast<const icmp6_hdr *>(tpHeader),
209 tpLen);
210 break;
211 case IPPROTO_TCP:
212 ret = ConvertTcpPacket(pos + IP_TP_PACKET_POSITION_DELTA, reinterpret_cast<const tcphdr *>(tpHeader),
213 oldChecksum, newChecksum, tpLen);
214 break;
215 case IPPROTO_UDP:
216 ret = ConvertUdpPacket(pos + IP_TP_PACKET_POSITION_DELTA, reinterpret_cast<const udphdr *>(tpHeader),
217 oldChecksum, newChecksum, tpLen);
218 break;
219 case IPPROTO_GRE:
220 case IPPROTO_ESP:
221 WritePayload(pos, tpHeader, tpLen);
222 ret = NETMANAGER_SUCCESS;
223 break;
224 default:
225 NETNATIVE_LOGW("unknown transport protocol");
226 ret = NETMANAGER_ERR_INVALID_PARAMETER;
227 }
228 ipHeader->tot_len = htons(ntohs(ipHeader->tot_len) + GetIovPacketLength(pos));
229 ipHeader->check = CalChecksum(ipHeader, sizeof(iphdr));
230 iovBufs_[pos].assign(reinterpret_cast<const char *>(ipHeader), iovBufLens_[pos]);
231 return ret;
232 }
233
IsV4PacketValid(const iphdr * ipHeader,size_t packetSize)234 bool ClatdPacketConverter::IsV4PacketValid(const iphdr *ipHeader, size_t packetSize)
235 {
236 if (packetSize < sizeof(iphdr)) {
237 NETNATIVE_LOGW("Invalid ipv4 packet, input packet size too small");
238 return false;
239 }
240 if (ipHeader->ihl * WORD_32BIT_IN_BYTE_UNIT < IPV4_HDR_MIN_LEN) {
241 NETNATIVE_LOGW("Invalid ipv4 packet, ip header length %{public}u smaller than 5", ipHeader->ihl);
242 return false;
243 }
244 if (static_cast<size_t>(ipHeader->ihl * WORD_32BIT_IN_BYTE_UNIT) > packetSize) {
245 NETNATIVE_LOGW("Invalid ipv4 packet, ip header length %{public}u larger than entire packet", ipHeader->ihl);
246 return false;
247 }
248 if (ipHeader->version != IPVERSION) {
249 NETNATIVE_LOGW("Invalid ipv4 packet, version %{public}u not 4", ipHeader->version);
250 return false;
251 }
252 return true;
253 }
254
IsV6PacketValid(const ip6_hdr * ip6Header,size_t packetSize)255 bool ClatdPacketConverter::IsV6PacketValid(const ip6_hdr *ip6Header, size_t packetSize)
256 {
257 if (packetSize < sizeof(ip6_hdr)) {
258 NETNATIVE_LOGW("Invalid ipv6 packet, input packet size too small");
259 return false;
260 }
261
262 if (IN6_IS_ADDR_MULTICAST(&ip6Header->ip6_dst)) {
263 NETNATIVE_LOGW("Invalid ipv6 packet, destination address is multicast");
264 return false;
265 }
266
267 if (!(std::equal(prefixAddr_.s6_addr, prefixAddr_.s6_addr + CLAT_PREFIX_BYTE_LEN, ip6Header->ip6_src.s6_addr) &&
268 IN6_ARE_ADDR_EQUAL(&ip6Header->ip6_dst, &localV6Addr_)) &&
269 !(std::equal(prefixAddr_.s6_addr, prefixAddr_.s6_addr + CLAT_PREFIX_BYTE_LEN, ip6Header->ip6_dst.s6_addr) &&
270 IN6_ARE_ADDR_EQUAL(&ip6Header->ip6_src, &localV6Addr_)) &&
271 ip6Header->ip6_nxt != IPPROTO_ICMPV6) {
272 NETNATIVE_LOGW("Invalid ipv6 packet, unknown source/destination address");
273 return false;
274 }
275
276 return true;
277 }
278
WriteIpv6Header(ip6_hdr * ip6Header,uint8_t tpProtocol,const iphdr * ipHeader)279 void ClatdPacketConverter::WriteIpv6Header(ip6_hdr *ip6Header, uint8_t tpProtocol, const iphdr *ipHeader)
280 {
281 ip6Header->ip6_vfc = IPV6_VERSION_FLAG;
282 ip6Header->ip6_plen = 0;
283 ip6Header->ip6_nxt = tpProtocol;
284 ip6Header->ip6_hlim = ipHeader->ttl;
285
286 ConvertV4Address(ipHeader->saddr, ip6Header->ip6_src);
287 ConvertV4Address(ipHeader->daddr, ip6Header->ip6_dst);
288 }
289
WriteIpv4Header(iphdr * ipHeader,uint8_t tpProtocol,const ip6_hdr * ip6Header)290 void ClatdPacketConverter::WriteIpv4Header(iphdr *ipHeader, uint8_t tpProtocol, const ip6_hdr *ip6Header)
291 {
292 ipHeader->ihl = (IPV4_HDR_MIN_LEN / WORD_32BIT_IN_BYTE_UNIT);
293 ipHeader->version = IPVERSION;
294 ipHeader->tos = 0;
295 ipHeader->tot_len = htons(sizeof(iphdr));
296 ipHeader->id = 0;
297 ipHeader->frag_off = htons(IP_DF);
298 ipHeader->ttl = ip6Header->ip6_hlim;
299 ipHeader->protocol = tpProtocol;
300 ipHeader->check = 0;
301
302 ConvertV6Address(ip6Header->ip6_src, ipHeader->saddr);
303 ConvertV6Address(ip6Header->ip6_dst, ipHeader->daddr);
304
305 if (static_cast<uint32_t>(ipHeader->saddr) == INADDR_NONE) {
306 ipHeader->saddr = htonl((0xffffff << CHAR_BIT) + ip6Header->ip6_hlim);
307 }
308 }
309
ConvertV4Address(uint32_t v4Addr,in6_addr & v6Addr)310 void ClatdPacketConverter::ConvertV4Address(uint32_t v4Addr, in6_addr &v6Addr)
311 {
312 if (v4Addr == localV4Addr_.s_addr) {
313 v6Addr = localV6Addr_;
314 } else {
315 v6Addr = prefixAddr_;
316 v6Addr.s6_addr32[CLAT_SUFFIX_OFFSET_IN_32] = v4Addr;
317 }
318 }
319
ConvertV6Address(const in6_addr & v6Addr,uint32_t & v4Addr)320 void ClatdPacketConverter::ConvertV6Address(const in6_addr &v6Addr, uint32_t &v4Addr)
321 {
322 if (std::equal(prefixAddr_.s6_addr, prefixAddr_.s6_addr + CLAT_PREFIX_BYTE_LEN, v6Addr.s6_addr)) {
323 v4Addr = v6Addr.s6_addr32[CLAT_SUFFIX_OFFSET_IN_32];
324 } else if (IN6_ARE_ADDR_EQUAL(&v6Addr, &localV6Addr_)) {
325 v4Addr = localV4Addr_.s_addr;
326 } else {
327 v4Addr = INADDR_NONE;
328 }
329 }
330
WriteFragHeader(ip6_frag * ip6FragHeader,ip6_hdr * ip6Header,const iphdr * ipHeader)331 size_t ClatdPacketConverter::WriteFragHeader(ip6_frag *ip6FragHeader, ip6_hdr *ip6Header, const iphdr *ipHeader)
332 {
333 uint16_t fragValue = ntohs(ipHeader->frag_off);
334 uint16_t fragOffset = fragValue & IP_OFFMASK;
335 if (fragOffset == 0 && (fragValue & IP_MF) == 0) {
336 return 0;
337 }
338
339 ip6FragHeader->ip6f_nxt = ip6Header->ip6_nxt;
340 ip6FragHeader->ip6f_reserved = 0;
341 ip6FragHeader->ip6f_offlg = htons(fragOffset << IPV6_FRAG_OFFSET_BIT_SUPPLEMENTARY);
342 if (fragValue & IP_MF) {
343 ip6FragHeader->ip6f_offlg |= IP6F_MORE_FRAG;
344 }
345 ip6FragHeader->ip6f_ident = htonl(ntohs(ipHeader->id));
346 ip6Header->ip6_nxt = IPPROTO_FRAGMENT;
347
348 return sizeof(*ip6FragHeader);
349 }
350
ProcessFragHeader(const ip6_frag * ip6FragHeader,iphdr * ipHeader,uint8_t & v6TpProtocol,uint8_t & v4TpProtocol)351 void ClatdPacketConverter::ProcessFragHeader(const ip6_frag *ip6FragHeader, iphdr *ipHeader, uint8_t &v6TpProtocol,
352 uint8_t &v4TpProtocol)
353 {
354 uint16_t fragOffset = ntohs(ip6FragHeader->ip6f_offlg & IP6F_OFF_MASK) >> IPV6_FRAG_OFFSET_BIT_SUPPLEMENTARY;
355 if (ip6FragHeader->ip6f_offlg & IP6F_MORE_FRAG) {
356 fragOffset |= IP_MF;
357 }
358 ipHeader->frag_off = htons(fragOffset);
359 ipHeader->id = htons(ntohl(ip6FragHeader->ip6f_ident) & 0xffff);
360
361 v6TpProtocol = ip6FragHeader->ip6f_nxt;
362 v4TpProtocol = v6TpProtocol == IPPROTO_ICMPV6 ? IPPROTO_ICMP : v6TpProtocol;
363 ipHeader->protocol = v4TpProtocol;
364 }
365
CalV4PseudoHeaderChecksum(const iphdr * ipHeader,uint16_t tpLen,uint8_t tpProtocol)366 uint32_t ClatdPacketConverter::CalV4PseudoHeaderChecksum(const iphdr *ipHeader, uint16_t tpLen, uint8_t tpProtocol)
367 {
368 uint16_t len = htons(tpLen);
369 uint16_t protocol = htons(tpProtocol);
370 uint32_t sum = 0;
371
372 sum = AddChecksum(sum, &(ipHeader->saddr), sizeof(uint32_t));
373 sum = AddChecksum(sum, &(ipHeader->daddr), sizeof(uint32_t));
374 sum = AddChecksum(sum, &len, sizeof(uint16_t));
375 sum = AddChecksum(sum, &protocol, sizeof(uint16_t));
376 return sum;
377 }
378
CalV6PseudoHeaderChecksum(const ip6_hdr * ip6Header,uint32_t tpLen,uint8_t tpProtocol)379 uint32_t ClatdPacketConverter::CalV6PseudoHeaderChecksum(const ip6_hdr *ip6Header, uint32_t tpLen, uint8_t tpProtocol)
380 {
381 uint32_t len = htonl(tpLen);
382 uint32_t protocol = htonl(tpProtocol);
383 uint32_t sum = 0;
384
385 sum = AddChecksum(sum, &(ip6Header->ip6_src), sizeof(in6_addr));
386 sum = AddChecksum(sum, &(ip6Header->ip6_dst), sizeof(in6_addr));
387 sum = AddChecksum(sum, &len, sizeof(uint32_t));
388 sum = AddChecksum(sum, &protocol, sizeof(uint32_t));
389 return sum;
390 }
391
GetIovPacketLength(int pos)392 uint16_t ClatdPacketConverter::GetIovPacketLength(int pos)
393 {
394 size_t sum = 0;
395 for (size_t i = pos + 1; i < static_cast<int>(CLATD_MAX); i++) {
396 sum += iovBufLens_[i];
397 }
398 return sum;
399 }
400
ConvertIcmpPacket(int pos,const icmphdr * icmpHeader,uint32_t checksum,size_t tpLen)401 int32_t ClatdPacketConverter::ConvertIcmpPacket(int pos, const icmphdr *icmpHeader, uint32_t checksum, size_t tpLen)
402 {
403 if (tpLen < sizeof(icmphdr)) {
404 NETNATIVE_LOGW("fail to convert icmp packet, packet length is too small");
405 effectivePos_ = 0;
406 return NETMANAGER_ERR_INVALID_PARAMETER;
407 }
408
409 icmp6_hdr icmp6Header;
410
411 ConvertIcmpTypeAndCode(icmpHeader->type, icmpHeader->code, icmp6Header.icmp6_type, icmp6Header.icmp6_code);
412
413 iovBufLens_[pos] = sizeof(icmp6_hdr);
414
415 const uint8_t *payload = reinterpret_cast<const uint8_t *>(icmpHeader + 1);
416 size_t payloadLen = tpLen - sizeof(icmphdr);
417
418 int32_t ret;
419 if (pos == static_cast<int>(CLATD_TPHDR) &&
420 (icmp6Header.icmp6_type == ICMP6_DST_UNREACH || icmp6Header.icmp6_type == ICMP6_TIME_EXCEEDED)) {
421 ret = ConvertV4Packet(pos + 1, payload, payloadLen);
422
423 checksum = checksum + htons(IPV6_HDR_LEN - IPV4_HDR_MIN_LEN);
424 } else if (icmp6Header.icmp6_type == ICMP6_ECHO_REQUEST || icmp6Header.icmp6_type == ICMP6_ECHO_REPLY) {
425 // Ping packet.
426 icmp6Header.icmp6_id = icmpHeader->un.echo.id;
427 icmp6Header.icmp6_seq = icmpHeader->un.echo.sequence;
428 iovBufs_[CLATD_PAYLOAD].assign(reinterpret_cast<const char *>(payload), payloadLen);
429 iovBufLens_[CLATD_PAYLOAD] = payloadLen;
430 effectivePos_ = CLATD_PAYLOAD + 1;
431 ret = NETMANAGER_SUCCESS;
432 } else {
433 effectivePos_ = 0;
434 ret = NETMANAGER_ERR_INVALID_PARAMETER;
435 }
436
437 icmp6Header.icmp6_cksum = 0;
438 iovBufs_[pos].assign(reinterpret_cast<const char *>(&icmp6Header), iovBufLens_[pos]);
439 icmp6Header.icmp6_cksum = CalIovPacketChecksum(checksum, pos);
440 iovBufs_[pos].assign(reinterpret_cast<const char *>(&icmp6Header), iovBufLens_[pos]);
441 return ret;
442 }
443
ConvertIcmpTypeAndCode(const uint8_t & icmpType,const uint8_t & icmpCode,uint8_t & icmp6Type,uint8_t & icmp6Code)444 void ClatdPacketConverter::ConvertIcmpTypeAndCode(const uint8_t &icmpType, const uint8_t &icmpCode, uint8_t &icmp6Type,
445 uint8_t &icmp6Code)
446 {
447 switch (icmpType) {
448 case ICMP_ECHO:
449 icmp6Type = ICMP6_ECHO_REQUEST;
450 icmp6Code = icmpCode;
451 break;
452 case ICMP_ECHOREPLY:
453 icmp6Type = ICMP6_ECHO_REPLY;
454 icmp6Code = icmpCode;
455 break;
456 case ICMP_TIME_EXCEEDED:
457 icmp6Type = ICMP6_TIME_EXCEEDED;
458 icmp6Code = icmpCode;
459 break;
460 case ICMP_DEST_UNREACH:
461 switch (icmpCode) {
462 case ICMP_UNREACH_NET:
463 case ICMP_UNREACH_HOST:
464 case ICMP_UNREACH_SRCFAIL:
465 case ICMP_UNREACH_NET_UNKNOWN:
466 case ICMP_UNREACH_HOST_UNKNOWN:
467 case ICMP_UNREACH_ISOLATED:
468 case ICMP_UNREACH_TOSNET:
469 case ICMP_UNREACH_TOSHOST:
470 icmp6Type = ICMP6_DST_UNREACH;
471 icmp6Code = ICMP6_DST_UNREACH_NOROUTE;
472 break;
473 case ICMP_UNREACH_PORT:
474 icmp6Type = ICMP6_DST_UNREACH;
475 icmp6Code = ICMP6_DST_UNREACH_NOPORT;
476 break;
477 case ICMP_UNREACH_NET_PROHIB:
478 case ICMP_UNREACH_HOST_PROHIB:
479 case ICMP_UNREACH_FILTER_PROHIB:
480 case ICMP_UNREACH_PRECEDENCE_CUTOFF:
481 icmp6Type = ICMP6_DST_UNREACH;
482 icmp6Code = ICMP6_DST_UNREACH_ADMIN;
483 break;
484 default:
485 icmp6Type = ICMP6_PARAM_PROB;
486 NETNATIVE_LOGW("fail to convert icmp packet type %{public}d code %{public}d", icmpType, icmpCode);
487 break;
488 }
489 break;
490 default:
491 NETNATIVE_LOGW("fail to convert icmp packet type %{public}d", icmpType);
492 icmp6Type = ICMP6_PARAM_PROB;
493 }
494 }
495
ConvertIcmpv6Packet(int pos,const icmp6_hdr * icmp6Header,size_t tpLen)496 int32_t ClatdPacketConverter::ConvertIcmpv6Packet(int pos, const icmp6_hdr *icmp6Header, size_t tpLen)
497 {
498 if (tpLen < sizeof(icmp6_hdr)) {
499 NETNATIVE_LOGW("fail to convert icmp6 packet, packet length is too small");
500 effectivePos_ = 0;
501 return NETMANAGER_ERR_INVALID_PARAMETER;
502 }
503
504 icmphdr icmpHeader;
505 ConvertIcmpV6TypeAndCode(icmp6Header->icmp6_type, icmp6Header->icmp6_code, icmpHeader.type, icmpHeader.code);
506 iovBufLens_[pos] = sizeof(icmphdr);
507
508 const uint8_t *payload = reinterpret_cast<const uint8_t *>(icmp6Header + 1);
509 size_t payloadLen = tpLen - sizeof(icmp6_hdr);
510 int32_t ret;
511 if (pos == CLATD_TPHDR && icmp6Header->icmp6_type < ICMP6_ECHO_REQUEST && icmpHeader.type != ICMP_PARAMETERPROB) {
512 ret = ConvertV6Packet(pos + 1, payload, payloadLen);
513 } else if (icmpHeader.type == ICMP_ECHO || icmpHeader.type == ICMP_ECHOREPLY) {
514 // Ping packet.
515 icmpHeader.un.echo.id = icmp6Header->icmp6_id;
516 icmpHeader.un.echo.sequence = icmp6Header->icmp6_seq;
517 iovBufs_[CLATD_PAYLOAD].assign(reinterpret_cast<const char *>(payload), payloadLen);
518 iovBufLens_[CLATD_PAYLOAD] = payloadLen;
519 effectivePos_ = CLATD_PAYLOAD + 1;
520 ret = NETMANAGER_SUCCESS;
521 } else {
522 effectivePos_ = 0;
523 ret = NETMANAGER_ERR_INVALID_PARAMETER;
524 }
525
526 icmpHeader.checksum = 0;
527 iovBufs_[pos].assign(reinterpret_cast<const char *>(&icmpHeader), iovBufLens_[pos]);
528 icmpHeader.checksum = CalIovPacketChecksum(0, pos);
529 iovBufs_[pos].assign(reinterpret_cast<const char *>(&icmpHeader), iovBufLens_[pos]);
530
531 return ret;
532 }
533
ConvertIcmpV6TypeAndCode(const uint8_t & icmp6Type,const uint8_t & icmp6Code,uint8_t & icmpType,uint8_t & icmpCode)534 void ClatdPacketConverter::ConvertIcmpV6TypeAndCode(const uint8_t &icmp6Type, const uint8_t &icmp6Code,
535 uint8_t &icmpType, uint8_t &icmpCode)
536 {
537 switch (icmp6Type) {
538 case ICMP6_ECHO_REQUEST:
539 icmpType = ICMP_ECHO;
540 icmpCode = icmp6Code;
541 break;
542 case ICMP6_ECHO_REPLY:
543 icmpType = ICMP_ECHOREPLY;
544 icmpCode = icmp6Code;
545 break;
546 case ICMP6_TIME_EXCEEDED:
547 icmpType = ICMP_TIME_EXCEEDED;
548 icmpCode = icmp6Code;
549 break;
550 case ICMP6_DST_UNREACH:
551 switch (icmp6Code) {
552 case ICMP6_DST_UNREACH_NOROUTE:
553 case ICMP6_DST_UNREACH_BEYONDSCOPE:
554 case ICMP6_DST_UNREACH_ADDR:
555 icmpType = ICMP_DEST_UNREACH;
556 icmpCode = ICMP_UNREACH_HOST;
557 break;
558
559 case ICMP6_DST_UNREACH_ADMIN:
560 icmpType = ICMP_DEST_UNREACH;
561 icmpCode = ICMP_UNREACH_HOST_PROHIB;
562 break;
563
564 case ICMP6_DST_UNREACH_NOPORT:
565 icmpType = ICMP_DEST_UNREACH;
566 icmpCode = ICMP_UNREACH_PORT;
567 break;
568 default:
569 NETNATIVE_LOGW("fail to convert icmpv6 packet type %{public}d", icmp6Type);
570 icmpType = ICMP_PARAMETERPROB;
571 }
572 break;
573 default:
574 NETNATIVE_LOGW("fail to convert icmpv6 packet type %{public}d", icmp6Type);
575 icmpType = ICMP_PARAMETERPROB;
576 }
577 }
578
CalIovPacketChecksum(uint32_t sum,int pos)579 uint16_t ClatdPacketConverter::CalIovPacketChecksum(uint32_t sum, int pos)
580 {
581 for (size_t i = pos; i < CLATD_MAX; i++) {
582 if (iovBufLens_[i] > 0) {
583 sum = AddChecksum(sum, iovBufs_[i].data(), iovBufLens_[i]);
584 }
585 }
586 return ~Checksum32To16(sum);
587 }
588
ConvertTcpPacket(int pos,const tcphdr * tcpHeader,uint32_t oldChecksum,uint32_t newChecksum,size_t tpLen)589 int32_t ClatdPacketConverter::ConvertTcpPacket(int pos, const tcphdr *tcpHeader, uint32_t oldChecksum,
590 uint32_t newChecksum, size_t tpLen)
591 {
592 if (!IsTcpPacketValid(tcpHeader, tpLen)) {
593 return NETMANAGER_ERR_INVALID_PARAMETER;
594 }
595
596 size_t tcpHdrLen = tcpHeader->doff * WORD_32BIT_IN_BYTE_UNIT;
597 iovBufLens_[pos] = tcpHdrLen;
598
599 char tcpHdrBuf[TCP_HDR_MAX_LEN];
600 if (memcpy_s(tcpHdrBuf, TCP_HDR_MAX_LEN, tcpHeader, tcpHdrLen) != EOK) {
601 return NETMANAGER_ERR_OPERATION_FAILED;
602 }
603 tcphdr *tcpHeaderOut = reinterpret_cast<tcphdr *>(tcpHdrBuf);
604
605 iovBufs_[CLATD_PAYLOAD].assign(reinterpret_cast<const char *>(tcpHeader) + tcpHdrLen, tpLen - tcpHdrLen);
606 iovBufLens_[CLATD_PAYLOAD] = tpLen - tcpHdrLen;
607 tcpHeaderOut->check = AdjustChecksum(tcpHeader->check, oldChecksum, newChecksum);
608 iovBufs_[pos].assign(reinterpret_cast<const char *>(tcpHdrBuf), tcpHdrLen);
609 effectivePos_ = CLATD_PAYLOAD + 1;
610 return NETMANAGER_SUCCESS;
611 }
612
IsTcpPacketValid(const tcphdr * tcpHeader,size_t packetSize)613 bool ClatdPacketConverter::IsTcpPacketValid(const tcphdr *tcpHeader, size_t packetSize)
614 {
615 if (packetSize < sizeof(tcphdr)) {
616 NETNATIVE_LOGW("Invalid tcp packet, packet length is too small");
617 effectivePos_ = 0;
618 return false;
619 }
620
621 if (tcpHeader->doff * WORD_32BIT_IN_BYTE_UNIT < TCP_HDR_MIN_LEN) {
622 NETNATIVE_LOGW("Invalid tcp packet, tcp header length %{public}u smaller than 5", tcpHeader->doff);
623 effectivePos_ = 0;
624 return false;
625 }
626
627 if (static_cast<size_t>(tcpHeader->doff * WORD_32BIT_IN_BYTE_UNIT) > packetSize) {
628 NETNATIVE_LOGW("Invalid tcp packet, tcp header length %{public}u larger than entire packet", tcpHeader->doff);
629 effectivePos_ = 0;
630 return false;
631 }
632
633 if (tcpHeader->doff * WORD_32BIT_IN_BYTE_UNIT > TCP_HDR_MAX_LEN) {
634 NETNATIVE_LOGW("Invalid tcp packet, tcp header length %{public}u larger than MAX_TCP_HDR", tcpHeader->doff);
635 effectivePos_ = 0;
636 return false;
637 }
638 return true;
639 }
640
ConvertUdpPacket(int pos,const udphdr * udpHeader,uint32_t oldChecksum,uint32_t newChecksum,size_t tpLen)641 int32_t ClatdPacketConverter::ConvertUdpPacket(int pos, const udphdr *udpHeader, uint32_t oldChecksum,
642 uint32_t newChecksum, size_t tpLen)
643 {
644 if (tpLen < sizeof(udphdr)) {
645 NETNATIVE_LOGW("Invalid udp packet, packet length is too small");
646 effectivePos_ = 0;
647 return NETMANAGER_ERR_INVALID_PARAMETER;
648 }
649
650 iovBufLens_[pos] = sizeof(udphdr);
651
652 iovBufLens_[CLATD_PAYLOAD] = tpLen - sizeof(udphdr);
653 iovBufs_[CLATD_PAYLOAD].assign(reinterpret_cast<const char *>(udpHeader + 1), tpLen - sizeof(udphdr));
654
655 udphdr udpHeaderOut = *udpHeader;
656 // details about zero checksum in RFC 768
657 if (udpHeaderOut.check == 0) {
658 iovBufs_[pos].assign(reinterpret_cast<const char *>(&udpHeaderOut), sizeof(udphdr));
659 udpHeaderOut.check = CalIovPacketChecksum(newChecksum, pos);
660 } else {
661 udpHeaderOut.check = AdjustChecksum(udpHeader->check, oldChecksum, newChecksum);
662 }
663
664 if (udpHeaderOut.check == 0) {
665 udpHeaderOut.check = 0xffff;
666 }
667 iovBufs_[pos].assign(reinterpret_cast<const char *>(&udpHeaderOut), sizeof(udphdr));
668 effectivePos_ = CLATD_PAYLOAD + 1;
669 return NETMANAGER_SUCCESS;
670 }
671
WritePayload(int pos,const uint8_t * tpHeader,size_t tpLen)672 void ClatdPacketConverter::WritePayload(int pos, const uint8_t *tpHeader, size_t tpLen)
673 {
674 iovBufLens_[pos + IP_TP_PACKET_POSITION_DELTA] = 0;
675 iovBufs_[CLATD_PAYLOAD].assign(reinterpret_cast<const char *>(tpHeader), tpLen);
676 iovBufLens_[CLATD_PAYLOAD] = tpLen;
677 effectivePos_ = CLATD_MAX;
678 }
679
WriteTunHeader(bool skip_csum)680 void ClatdPacketConverter::WriteTunHeader(bool skip_csum)
681 {
682 tun_pi tunProtocolInfo;
683 if (skip_csum) {
684 tunProtocolInfo.flags = htons(TP_CSUM_UNNECESSARY);
685 } else {
686 tunProtocolInfo.flags = 0;
687 }
688 tunProtocolInfo.proto = htons(ETH_P_IP);
689 iovBufLens_[CLATD_TUNHDR] = sizeof(tun_pi);
690 iovBufs_[CLATD_TUNHDR].assign(reinterpret_cast<const char *>(&tunProtocolInfo), sizeof(tun_pi));
691 }
692
693 } // namespace nmd
694 } // namespace OHOS