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