1 /*
2 * Copyright (c) 2022, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "net/nat64_translator.hpp"
30
31 #include "test_platform.h"
32 #include "test_util.hpp"
33
34 #include "string.h"
35
36 #include "common/code_utils.hpp"
37 #include "common/debug.hpp"
38 #include "common/instance.hpp"
39 #include "common/message.hpp"
40 #include "net/ip6.hpp"
41
42 #if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
43
44 namespace ot {
45 namespace BorderRouter {
46
47 static ot::Instance *sInstance;
48
DumpMessageInHex(const char * prefix,const uint8_t * aBuf,size_t aBufLen)49 void DumpMessageInHex(const char *prefix, const uint8_t *aBuf, size_t aBufLen)
50 {
51 // This function dumps all packets the output of this function can be imported to packet analyser for debugging.
52 printf("%s", prefix);
53 for (uint16_t i = 0; i < aBufLen; i++)
54 {
55 printf("%02x", aBuf[i]);
56 }
57 printf("\n");
58 }
59
CheckMessage(const Message & aMessage,const uint8_t * aExpectedMessage,size_t aExpectedMessageLen)60 bool CheckMessage(const Message &aMessage, const uint8_t *aExpectedMessage, size_t aExpectedMessageLen)
61 {
62 uint8_t readMessage[OPENTHREAD_CONFIG_IP6_MAX_DATAGRAM_LENGTH];
63 uint16_t messageLength;
64 bool success = true;
65
66 success = success && (aMessage.GetLength() == aExpectedMessageLen);
67 messageLength = aMessage.ReadBytes(0, readMessage, aMessage.GetLength());
68 success = success && (aExpectedMessageLen == messageLength);
69 success = success && (memcmp(readMessage, aExpectedMessage, aExpectedMessageLen) == 0);
70
71 if (!success)
72 {
73 printf("Expected Message\n");
74 for (uint16_t i = 0; i < aExpectedMessageLen; i++)
75 {
76 printf("%02x%c", aExpectedMessage[i], " \n"[(i & 0xf) == 0xf]);
77 }
78 printf("\n");
79 printf("Actual Message\n");
80 for (uint16_t i = 0; i < messageLength; i++)
81 {
82 printf("%02x%c", readMessage[i], " \n"[(i & 0xf) == 0xf]);
83 }
84 printf("\n");
85 }
86
87 return success;
88 }
89
90 template <size_t N>
TestCase6To4(const char * aTestName,const uint8_t (& aIp6Message)[N],Nat64::Translator::Result aResult,const uint8_t * aOutMessage,size_t aOutMessageLen)91 void TestCase6To4(const char *aTestName,
92 const uint8_t (&aIp6Message)[N],
93 Nat64::Translator::Result aResult,
94 const uint8_t *aOutMessage,
95 size_t aOutMessageLen)
96 {
97 Message *msg = sInstance->Get<Ip6::Ip6>().NewMessage(0);
98
99 printf("Testing NAT64 6 to 4: %s\n", aTestName);
100
101 VerifyOrQuit(msg != nullptr);
102 SuccessOrQuit(msg->AppendBytes(aIp6Message, N));
103
104 DumpMessageInHex("I ", aIp6Message, N);
105
106 VerifyOrQuit(sInstance->Get<Nat64::Translator>().TranslateFromIp6(*msg) == aResult);
107
108 if (aOutMessage != nullptr)
109 {
110 DumpMessageInHex("O ", aOutMessage, aOutMessageLen);
111 VerifyOrQuit(CheckMessage(*msg, aOutMessage, aOutMessageLen));
112 }
113
114 printf(" ... PASS\n");
115 }
116
117 template <size_t N>
TestCase4To6(const char * aTestName,const uint8_t (& aIp4Message)[N],Nat64::Translator::Result aResult,const uint8_t * aOutMessage,size_t aOutMessageLen)118 void TestCase4To6(const char *aTestName,
119 const uint8_t (&aIp4Message)[N],
120 Nat64::Translator::Result aResult,
121 const uint8_t *aOutMessage,
122 size_t aOutMessageLen)
123 {
124 Message *msg = sInstance->Get<Ip6::Ip6>().NewMessage(0);
125
126 printf("Testing NAT64 4 to 6: %s\n", aTestName);
127
128 VerifyOrQuit(msg != nullptr);
129 SuccessOrQuit(msg->AppendBytes(aIp4Message, N));
130
131 DumpMessageInHex("I ", aIp4Message, N);
132
133 VerifyOrQuit(sInstance->Get<Nat64::Translator>().TranslateToIp6(*msg) == aResult);
134
135 if (aOutMessage != nullptr)
136 {
137 DumpMessageInHex("O ", aOutMessage, aOutMessageLen);
138 VerifyOrQuit(CheckMessage(*msg, aOutMessage, aOutMessageLen));
139 }
140
141 printf(" ... PASS\n");
142 }
143
TestNat64(void)144 void TestNat64(void)
145 {
146 Ip6::Prefix nat64prefix;
147 Ip4::Cidr nat64cidr;
148 Ip6::Address ip6Source;
149 Ip6::Address ip6Dest;
150
151 sInstance = testInitInstance();
152
153 {
154 const uint8_t ip6Address[] = {0xfd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
155 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
156 const uint8_t ip4Address[] = {192, 168, 123, 1};
157
158 nat64cidr.Set(ip4Address, 32);
159 nat64prefix.Set(ip6Address, 96);
160 SuccessOrQuit(sInstance->Get<Nat64::Translator>().SetIp4Cidr(nat64cidr));
161 sInstance->Get<Nat64::Translator>().SetNat64Prefix(nat64prefix);
162 }
163
164 {
165 // fd02::1 fd01::ac10:f3c5 UDP 52 43981 → 4660 Len=4
166 const uint8_t kIp6Packet[] = {
167 0x60, 0x08, 0x6e, 0x38, 0x00, 0x0c, 0x11, 0x40, 0xfd, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
168 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xfd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
169 172, 16, 243, 197, 0xab, 0xcd, 0x12, 0x34, 0x00, 0x0c, 0xe3, 0x31, 0x61, 0x62, 0x63, 0x64,
170 };
171 // 192.168.123.1 172.16.243.197 UDP 32 43981 → 4660 Len=4
172 const uint8_t kIp4Packet[] = {0x45, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x40, 0x11, 0x9f,
173 0x4d, 192, 168, 123, 1, 172, 16, 243, 197, 0xab, 0xcd,
174 0x12, 0x34, 0x00, 0x0c, 0xa1, 0x8d, 0x61, 0x62, 0x63, 0x64};
175
176 TestCase6To4("good v6 udp datagram", kIp6Packet, Nat64::Translator::kForward, kIp4Packet, sizeof(kIp4Packet));
177 }
178
179 {
180 // 172.16.243.197 192.168.123.1 UDP 32 43981 → 4660 Len=4
181 const uint8_t kIp4Packet[] = {0x45, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x11, 0xa0,
182 0x4d, 172, 16, 243, 197, 192, 168, 123, 1, 0xab, 0xcd,
183 0x12, 0x34, 0x00, 0x0c, 0xa1, 0x8d, 0x61, 0x62, 0x63, 0x64};
184 // fd01::ac10:f3c5 fd02::1 UDP 52 43981 → 4660 Len=4
185 const uint8_t kIp6Packet[] = {
186 0x60, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x11, 0x3f, 0xfd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
187 0x00, 0x00, 172, 16, 243, 197, 0xfd, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
188 0x00, 0x00, 0x00, 0x01, 0xab, 0xcd, 0x12, 0x34, 0x00, 0x0c, 0xe3, 0x31, 0x61, 0x62, 0x63, 0x64,
189 };
190
191 TestCase4To6("good v4 udp datagram", kIp4Packet, Nat64::Translator::kForward, kIp6Packet, sizeof(kIp6Packet));
192 }
193
194 {
195 // fd02::1 fd01::ac10:f3c5 TCP 64 43981 → 4660 [ACK] Seq=1 Ack=1 Win=1 Len=4
196 const uint8_t kIp6Packet[] = {
197 0x60, 0x08, 0x6e, 0x38, 0x00, 0x18, 0x06, 0x40, 0xfd, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
198 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xfd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
199 0x00, 0x00, 0x00, 0x00, 172, 16, 243, 197, 0xab, 0xcd, 0x12, 0x34, 0x87, 0x65, 0x43, 0x21,
200 0x12, 0x34, 0x56, 0x78, 0x50, 0x10, 0x00, 0x01, 0x5f, 0xf8, 0x00, 0x00, 0x61, 0x62, 0x63, 0x64,
201 };
202 // 192.168.123.1 172.16.243.197 TCP 44 43981 → 4660 [ACK] Seq=1 Ack=1 Win=1 Len=4
203 const uint8_t kIp4Packet[] = {0x45, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x9f,
204 0x4c, 192, 168, 123, 1, 172, 16, 243, 197, 0xab, 0xcd,
205 0x12, 0x34, 0x87, 0x65, 0x43, 0x21, 0x12, 0x34, 0x56, 0x78, 0x50,
206 0x10, 0x00, 0x01, 0x1e, 0x54, 0x00, 0x00, 0x61, 0x62, 0x63, 0x64};
207
208 TestCase6To4("good v6 tcp datagram", kIp6Packet, Nat64::Translator::kForward, kIp4Packet, sizeof(kIp4Packet));
209 }
210
211 {
212 // 172.16.243.197 192.168.123.1 TCP 44 43981 → 4660 [ACK] Seq=1 Ack=1 Win=1 Len=4
213 const uint8_t kIp4Packet[] = {0x45, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x9f,
214 0x4c, 172, 16, 243, 197, 192, 168, 123, 1, 0xab, 0xcd,
215 0x12, 0x34, 0x87, 0x65, 0x43, 0x21, 0x12, 0x34, 0x56, 0x78, 0x50,
216 0x10, 0x00, 0x01, 0x1e, 0x54, 0x00, 0x00, 0x61, 0x62, 0x63, 0x64};
217 // fd01::ac10:f3c5 fd02::1 TCP 64 43981 → 4660 [ACK] Seq=1 Ack=1 Win=1 Len=4
218 const uint8_t kIp6Packet[] = {
219 0x60, 0x00, 0x00, 0x00, 0x00, 0x18, 0x06, 0x40, 0xfd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
220 0x00, 0x00, 0x00, 0x00, 172, 16, 243, 197, 0xfd, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
221 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xab, 0xcd, 0x12, 0x34, 0x87, 0x65, 0x43, 0x21,
222 0x12, 0x34, 0x56, 0x78, 0x50, 0x10, 0x00, 0x01, 0x5f, 0xf8, 0x00, 0x00, 0x61, 0x62, 0x63, 0x64,
223 };
224
225 TestCase4To6("good v4 tcp datagram", kIp4Packet, Nat64::Translator::kForward, kIp6Packet, sizeof(kIp6Packet));
226 }
227
228 {
229 // fd02::1 fd01::ac10:f3c5 ICMPv6 52 Echo (ping) request id=0xaabb, seq=1, hop limit=64
230 const uint8_t kIp6Packet[] = {
231 0x60, 0x08, 0x6e, 0x38, 0x00, 0x0c, 0x3a, 0x40, 0xfd, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
232 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xfd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
233 172, 16, 243, 197, 0x80, 0x00, 0x76, 0x59, 0xaa, 0xbb, 0x00, 0x01, 0x61, 0x62, 0x63, 0x64,
234 };
235 // 192.168.123.1 172.16.243.197 ICMP 32 Echo (ping) request id=0xaabb, seq=1/256, ttl=63
236 const uint8_t kIp4Packet[] = {0x45, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x9f,
237 0x5d, 192, 168, 123, 1, 172, 16, 243, 197, 0x08, 0x00,
238 0x88, 0x7c, 0xaa, 0xbb, 0x00, 0x01, 0x61, 0x62, 0x63, 0x64};
239
240 TestCase6To4("good v6 icmp ping request datagram", kIp6Packet, Nat64::Translator::kForward, kIp4Packet,
241 sizeof(kIp4Packet));
242 }
243
244 {
245 // 172.16.243.197 192.168.123.1 ICMP 32 Echo (ping) reply id=0xaabb, seq=1/256, ttl=63
246 const uint8_t kIp4Packet[] = {0x45, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x01, 0xa0,
247 0x5d, 172, 16, 243, 197, 192, 168, 123, 1, 0x00, 0x00,
248 0x90, 0x7c, 0xaa, 0xbb, 0x00, 0x01, 0x61, 0x62, 0x63, 0x64};
249 // fd01::ac10:f3c5 fd02::1 ICMPv6 52 Echo (ping) reply id=0xaabb, seq=1, hop limit=62
250 const uint8_t kIp6Packet[] = {
251 0x60, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x3a, 0x3f, 0xfd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
252 0x00, 0x00, 172, 16, 243, 197, 0xfd, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
253 0x00, 0x00, 0x00, 0x01, 0x81, 0x00, 0x75, 0x59, 0xaa, 0xbb, 0x00, 0x01, 0x61, 0x62, 0x63, 0x64,
254 };
255
256 TestCase4To6("good v4 icmp ping response datagram", kIp4Packet, Nat64::Translator::kForward, kIp6Packet,
257 sizeof(kIp6Packet));
258 }
259
260 {
261 // fd02::1 N/A IPv6 39 Invalid IPv6 header
262 const uint8_t kIp6Packet[] = {0x60, 0x08, 0x6e, 0x38, 0x00, 0x0c, 0x11, 0x40, 0xfd, 0x02, 0x00, 0x00, 0x00,
263 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xfd, 0x01,
264 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 172, 16, 243};
265
266 TestCase6To4("bad v6 datagram", kIp6Packet, Nat64::Translator::kDrop, nullptr, 0);
267 }
268
269 {
270 // 172.16.243.197 N/A IPv4 19 [Malformed Packet]
271 const uint8_t kIp4Packet[] = {0x45, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x11,
272 0xa0, 0x4c, 172, 16, 243, 197, 192, 168, 123};
273
274 TestCase4To6("bad v4 datagram", kIp4Packet, Nat64::Translator::kDrop, nullptr, 0);
275 }
276
277 {
278 // 172.16.243.197 192.168.123.2 UDP 32 43981 → 4660 Len=4
279 const uint8_t kIp4Packet[] = {0x45, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x11, 0xa0,
280 0x4c, 172, 16, 243, 197, 192, 168, 123, 2, 0xab, 0xcd,
281 0x12, 0x34, 0x00, 0x0c, 0xa1, 0x8c, 0x61, 0x62, 0x63, 0x64};
282
283 TestCase4To6("no v4 mapping", kIp4Packet, Nat64::Translator::kDrop, nullptr, 0);
284 }
285
286 {
287 // fd02::2 fd01::ac10:f3c5 UDP 52 43981 → 4660 Len=4
288 const uint8_t kIp6Packet[] = {
289 0x60, 0x08, 0x6e, 0x38, 0x00, 0x0c, 0x11, 0x40, 0xfd, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
290 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xfd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
291 172, 16, 243, 197, 0xab, 0xcd, 0x12, 0x34, 0x00, 0x0c, 0xe3, 0x30, 0x61, 0x62, 0x63, 0x64,
292 };
293
294 TestCase6To4("mapping pool exhausted", kIp6Packet, Nat64::Translator::kDrop, nullptr, 0);
295 }
296
297 testFreeInstance(sInstance);
298 }
299
300 } // namespace BorderRouter
301 } // namespace ot
302
303 #endif // OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
304
main(void)305 int main(void)
306 {
307 #if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
308 ot::BorderRouter::TestNat64();
309 printf("All tests passed\n");
310 #else // OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
311 printf("NAT64 is not enabled\n");
312 #endif // OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
313 return 0;
314 }
315