1 /*
2 * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
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 * Description: according the rfc 6052, the prefix length could be 32/40/48/56/64/96.
15 * but only 96 prefix length can be supported in our nat64 now.
16 * when the rpl start, the prefix will be setted, now this prefix is used in nat64.
17 * noted:this prefix should be stored independently in nat64 when needed.
18 * Author: NA
19 * Create: 2019
20 */
21 #include "lwip/opt.h"
22 #include "lwip/dhcp.h"
23 #if LWIP_NAT64
24 #include "lwip/pbuf.h"
25 #include "lwip/netif.h"
26 #include "lwip/ip.h"
27 #include "lwip/nat64.h"
28 #include "lwip/lwip_rpl.h"
29 #include "lwip/nat64_addr.h"
30 #include "lwip/nat64_dns64.h"
31
32 /* maybe the prefix can be stored */
33 int
nat64_stateless_addr_4to6(const ip4_addr_t * ip4addr,ip6_addr_t * ip6addr)34 nat64_stateless_addr_4to6(const ip4_addr_t *ip4addr, ip6_addr_t *ip6addr)
35 {
36 ip6_addr_t prefix;
37 uint8_t len;
38 err_t err;
39
40 if ((ip4addr == NULL) || (ip6addr == NULL)) {
41 return -1;
42 }
43 (void)memset_s(&prefix, sizeof(ip6_addr_t), 0, sizeof(ip6_addr_t));
44 #ifdef NAT64_USING_DAG_PREFIX
45 err = lwip_rpl_get_default_prefix(&prefix, &len);
46 #elif LWIP_DNS64
47 err = nat64_dns64_get_prefix(&prefix, &len);
48 #else
49 err = ERR_VAL;
50 #endif
51 if (err != ERR_OK) {
52 return -1;
53 }
54
55 (void)len;
56 /* the address convert should be related with the prefix len, here is for simple */
57 ip6_addr_copy_ptr(ip6addr, &prefix);
58 /* the last 32bit address of ipv6 is ipv4 address. */
59 ip6addr->addr[3] = ip4addr->addr;
60
61 return 0;
62 }
63
64 /* handle special prefix or different prefix length */
65 int
nat64_stateless_addr_6to4(const ip6_addr_t * ip6addr,ip4_addr_t * ip4addr)66 nat64_stateless_addr_6to4(const ip6_addr_t *ip6addr, ip4_addr_t *ip4addr)
67 {
68 ip6_addr_t prefix;
69 err_t err;
70
71 if ((ip4addr == NULL) || (ip6addr == NULL)) {
72 return -1;
73 }
74
75 if (nat64_addr_is_ip4(ip6addr) == 0) {
76 return -1;
77 }
78 /* the last 32bit address of ipv6 */
79 ip4addr->addr = ip6addr->addr[3];
80 (void)memset_s(&prefix, sizeof(ip6_addr_t), 0, sizeof(ip6_addr_t));
81 #ifdef LWIP_NAT64_SAME_PREFIX
82 uint8_t len;
83 err = lwip_rpl_get_default_prefix(&prefix, &len);
84 if (err != ERR_OK) {
85 return -1;
86 }
87
88 /* 96 prefix length is used now, should check that (96 - prefix.length) bit is zero */
89 if (memcmp(ip6addr, &prefix, len >> 3) == 0) {
90 ip4addr->addr = ip6addr->addr[3]; /* the last address of ipv6 */
91 return 0;
92 }
93
94 return -1;
95 #else
96 err = 0;
97 (void)err;
98 (void)prefix;
99 return 0;
100 #endif
101 }
102
103 int
nat64_entry_to6(const nat64_entry_t * entry,ip6_addr_t * ip6addr)104 nat64_entry_to6(const nat64_entry_t *entry, ip6_addr_t *ip6addr)
105 {
106 ip6_addr_t prefix;
107 uint8_t len;
108 err_t err;
109
110 if ((entry == NULL) || (ip6addr == NULL)) {
111 return -1;
112 }
113 (void)memset_s(&prefix, sizeof(ip6_addr_t), 0, sizeof(ip6_addr_t));
114 err = lwip_rpl_get_default_prefix(&prefix, &len);
115 if (err != ERR_OK) {
116 return -1;
117 }
118
119 (void)len;
120 ip6_addr_copy_ptr(ip6addr, &prefix);
121 lwip_rpl_set_ip6_iid(&entry->mac, entry->orig_mnid, ip6addr);
122
123 return 0;
124 }
125
126 int
nat64_entry_to4(const nat64_entry_t * entry,ip4_addr_t * ip4addr)127 nat64_entry_to4(const nat64_entry_t *entry, ip4_addr_t *ip4addr)
128 {
129 #if LWIP_NAT64_MIN_SUBSTITUTE
130 dhcp_num_t index = 0;
131 ip4_addr_t ip;
132 err_t ret;
133 #endif
134
135 #if LWIP_NAT64_MIN_SUBSTITUTE
136 ret = nat64_entry_mac_to_idx(entry->mac.addr, entry->mac.addrlen, &index);
137 if (ret != ERR_OK) {
138 return -1;
139 }
140 (void)memset_s(&ip, sizeof(ip4_addr_t), 0, sizeof(ip4_addr_t));
141 #endif
142
143 if ((entry->state == NAT64_STATE_ESTABLISH) &&
144 #if !LWIP_NAT64_MIN_SUBSTITUTE
145 (!ip4_addr_isany_val(entry->ip))
146 #elif LWIP_DHCP_SUBSTITUTE
147 (dhcp_substitute_idx_to_ip(nat64_netif_get(), index, &ip) == ERR_OK) &&
148 (!ip4_addr_isany_val(ip))
149 #else
150 (lwIP_FALSE)
151 #endif
152 ) {
153 #if !LWIP_NAT64_MIN_SUBSTITUTE
154 ip4_addr_copy(*ip4addr, entry->ip);
155 #elif LWIP_DHCP_SUBSTITUTE
156 ip4_addr_copy(*ip4addr, ip);
157 #else
158 ip4addr->addr = 0;
159 #endif
160 return 0;
161 }
162
163 return -1;
164 }
165
166 int
nat64_addr_6to4(const ip6_addr_t * ip6addr,ip4_addr_t * ip4addr)167 nat64_addr_6to4(const ip6_addr_t *ip6addr, ip4_addr_t *ip4addr)
168 {
169 linklayer_addr_t lladdr;
170 nat64_entry_t *entry = NULL;
171 int ret;
172
173 if ((ip4addr == NULL) || (ip6addr == NULL)) {
174 return -1;
175 }
176 /* 64ff:9b/96 prefix is unique */
177 ret = nat64_stateless_addr_6to4(ip6addr, ip4addr);
178 if (ret == 0) {
179 return 0;
180 }
181
182 ret = lwip_rpl_get_lladdr(ip6addr, &lladdr);
183 if (ret != ERR_OK) {
184 return -1;
185 }
186
187 entry = nat64_entry_lookup_by_mac(&lladdr);
188 if (entry == NULL) {
189 return -1;
190 }
191
192 return nat64_entry_to4(entry, ip4addr);
193 }
194
195 int
nat64_addr_is_ip4(const ip6_addr_t * ip6addr)196 nat64_addr_is_ip4(const ip6_addr_t *ip6addr)
197 {
198 ip6_addr_t prefix;
199 uint8_t len;
200 err_t err;
201
202 if (ip6addr == NULL) {
203 return 0;
204 }
205 (void)memset_s(&prefix, sizeof(ip6_addr_t), 0, sizeof(ip6_addr_t));
206 #ifdef NAT64_USING_DAG_PREFIX
207 err = lwip_rpl_get_default_prefix(&prefix, &len);
208 #elif LWIP_DNS64
209 err = nat64_dns64_get_prefix(&prefix, &len);
210 #else
211 err = ERR_VAL;
212 #endif
213 if (err != ERR_OK) {
214 return 0;
215 }
216 /* bit64~71 is not zero, the address is not ipv4 */
217 if (memcmp(&prefix, ip6addr, len >> 3) != 0) {
218 return 0;
219 }
220
221 return 1;
222 }
223
224 #endif
225