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