1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** NetX Duo Component */
16 /** */
17 /** Network Address Translation Protocol (NAT) */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22
23 #define NX_NAT_SOURCE_CODE
24
25
26 /* Force error checking to be disabled in this module */
27
28 #ifndef NX_DISABLE_ERROR_CHECKING
29 #define NX_DISABLE_ERROR_CHECKING
30 #endif
31
32
33 #include "tx_api.h"
34 #include "tx_thread.h"
35 #include "nx_api.h"
36 #include "nx_nat.h"
37 #include "nx_udp.h"
38 #include "nx_tcp.h"
39 #include "nx_icmp.h"
40 #include "nx_packet.h"
41 #include "nx_system.h"
42
43 #ifdef NX_NAT_ENABLE
44 /* Bring in externs for caller checking code. */
45
46 NX_CALLER_CHECKING_EXTERNS
47
48 /* Define */
49 NX_NAT_DEVICE *nat_server_ptr;
50
51
52 /* Define internal NAT services. */
53
54 static UINT _nx_nat_process_packet(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT packet_process);
55 static UINT _nx_nat_process_inbound_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr);
56 static UINT _nx_nat_process_inbound_TCP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr);
57 static UINT _nx_nat_process_inbound_UDP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr);
58 static UINT _nx_nat_process_inbound_ICMP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr);
59 static UINT _nx_nat_process_outbound_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr);
60 static UINT _nx_nat_process_outbound_TCP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr);
61 static UINT _nx_nat_process_outbound_UDP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr);
62 static UINT _nx_nat_process_outbound_ICMP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr);
63 static VOID _nx_nat_ip_packet_send(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr, UCHAR packet_type, ULONG next_hop_address);
64 static UINT _nx_nat_inbound_entry_find(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr, NX_NAT_TRANSLATION_ENTRY **matched_entry_ptr, ULONG *next_hop_address);
65 static UINT _nx_nat_outbound_entry_find(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr, NX_NAT_TRANSLATION_ENTRY **matched_entry_ptr, ULONG *next_hop_address);
66 static UINT _nx_nat_entry_create(NX_NAT_DEVICE *nat_ptr, UCHAR protocol, ULONG local_ip_address, ULONG peer_ip_address,
67 USHORT local_port, USHORT external_port, USHORT peer_port, ULONG response_timeout, NX_NAT_TRANSLATION_ENTRY **match_entry_ptr);
68 static UINT _nx_nat_entry_add(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr);
69 static VOID _nx_nat_entry_find(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *entry_to_match, NX_NAT_TRANSLATION_ENTRY **match_entry_ptr, UCHAR direction, UINT skip_static_entries);
70 static VOID _nx_nat_entry_timeout_check(NX_NAT_DEVICE *nat_ptr);
71 static UINT _nx_nat_packet_is_icmp_error_message(NX_PACKET *packet_ptr, UINT *is_icmp_error_msg);
72 static UINT _nx_nat_find_available_port(NX_NAT_DEVICE *nat_ptr, UCHAR protocol, USHORT *port);
73 static UINT _nx_nat_entry_port_verify(NX_IP *ip_ptr, UINT protocol, UINT port);
74 static UINT _nx_nat_socket_port_verify(NX_IP *ip_ptr, UINT protocol, UINT port);
75 static UINT _nx_nat_utility_get_source_port(NX_PACKET *packet_ptr, UCHAR protocol, USHORT *source_port);
76 static UINT _nx_nat_utility_get_destination_port(NX_PACKET *packet_ptr, UCHAR protocol, USHORT *destination_port);
77 static VOID _nx_nat_checksum_adjust(UCHAR *checksum, UCHAR *old_data, INT old_data_length, UCHAR *new_data, INT new_data_length);
78
79
80 /**************************************************************************/
81 /* */
82 /* FUNCTION RELEASE */
83 /* */
84 /* _nxe_nat_create PORTABLE C */
85 /* 6.1 */
86 /* AUTHOR */
87 /* */
88 /* Yuxin Zhou, Microsoft Corporation */
89 /* */
90 /* DESCRIPTION */
91 /* */
92 /* This function performs error checking on the create NAT service. */
93 /* */
94 /* INPUT */
95 /* */
96 /* nat_ptr Pointer to NAT instance */
97 /* ip_ptr Pointer to NAT IP instance */
98 /* global_interface_index Index of global interface */
99 /* dynamic_cache_memory Pointer to dynamic entry cache */
100 /* dynamic_cache_size The size of dynamic entry cache */
101 /* */
102 /* OUTPUT */
103 /* */
104 /* NX_PTR_ERROR Invalid pointer parameter */
105 /* NX_NAT_PARAM_ERROR Invalid non pointer input */
106 /* status Actual completion status */
107 /* */
108 /* CALLS */
109 /* */
110 /* _nx_nat_create Creates the NAT instance service */
111 /* */
112 /* CALLED BY */
113 /* */
114 /* Application Code */
115 /* */
116 /* RELEASE HISTORY */
117 /* */
118 /* DATE NAME DESCRIPTION */
119 /* */
120 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
121 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
122 /* resulting in version 6.1 */
123 /* */
124 /**************************************************************************/
_nxe_nat_create(NX_NAT_DEVICE * nat_ptr,NX_IP * ip_ptr,UINT global_interface_index,VOID * dynamic_cache_memory,UINT dynamic_cache_size)125 UINT _nxe_nat_create(NX_NAT_DEVICE *nat_ptr, NX_IP *ip_ptr, UINT global_interface_index, VOID *dynamic_cache_memory, UINT dynamic_cache_size)
126 {
127
128 UINT status;
129
130
131 /* Check for valid input pointers. */
132 if ((!nat_ptr) || (!ip_ptr))
133 {
134
135 /* Return pointer error. */
136 return(NX_PTR_ERROR);
137 }
138
139 /* Check for invalid non pointer input. */
140 if (ip_ptr -> nx_ip_id != NX_IP_ID)
141 {
142
143 /* Return pointer error. */
144 return(NX_NAT_PARAM_ERROR);
145 }
146
147 /* Check the interface index. */
148 if (global_interface_index >= NX_MAX_PHYSICAL_INTERFACES)
149 {
150
151 /* Return pointer error. */
152 return(NX_NAT_PARAM_ERROR);
153 }
154
155 /* Make sure entry cache is 4-byte aligned. */
156 if ((((UINT)dynamic_cache_memory & 0x3) != 0) ||
157 ((dynamic_cache_size & 0x3) != 0))
158 {
159
160 /* Return error status. */
161 return(NX_NAT_CACHE_ERROR);
162 }
163
164 /* Check the cache size. */
165 if (dynamic_cache_size < (NX_NAT_MIN_ENTRY_COUNT * sizeof (NX_NAT_TRANSLATION_ENTRY)))
166 {
167
168 /* Return error status. */
169 return(NX_NAT_CACHE_ERROR);
170 }
171
172 /* Call the actual NAT create service. */
173 status = _nx_nat_create(nat_ptr, ip_ptr, global_interface_index, dynamic_cache_memory, dynamic_cache_size);
174
175 /* Return completion status. */
176 return(status);
177 }
178
179
180 /**************************************************************************/
181 /* */
182 /* FUNCTION RELEASE */
183 /* */
184 /* _nx_nat_create PORTABLE C */
185 /* 6.1 */
186 /* AUTHOR */
187 /* */
188 /* Yuxin Zhou, Microsoft Corporation */
189 /* */
190 /* DESCRIPTION */
191 /* */
192 /* This function creates the NetX NAT instance and various NAT */
193 /* configuration options, it also creates the NAT mutex. */
194 /* */
195 /* INPUT */
196 /* */
197 /* nat_ptr Pointer to NAT instance */
198 /* ip_ptr Pointer to NAT IP instance */
199 /* global_interface_index Index of global interface */
200 /* dynamic_cache_memory Pointer to dynamic entry cache */
201 /* dynamic_cache_size The size of dynamic entry cache */
202 /* */
203 /* OUTPUT */
204 /* */
205 /* status Actual completion status */
206 /* NX_SUCCESS Successful completion */
207 /* NX_NAT_OVERLAPPING_SUBNET_ERROR Invalid NAT network interfaces */
208 /* */
209 /* CALLS */
210 /* */
211 /* tx_mutex_create Create NAT flag group mutex */
212 /* memset Clear specified area of memory */
213 /* */
214 /* CALLED BY */
215 /* */
216 /* Application code */
217 /* */
218 /* RELEASE HISTORY */
219 /* */
220 /* DATE NAME DESCRIPTION */
221 /* */
222 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
223 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
224 /* resulting in version 6.1 */
225 /* */
226 /**************************************************************************/
_nx_nat_create(NX_NAT_DEVICE * nat_ptr,NX_IP * ip_ptr,UINT global_interface_index,VOID * dynamic_cache_memory,UINT dynamic_cache_size)227 UINT _nx_nat_create(NX_NAT_DEVICE *nat_ptr, NX_IP *ip_ptr, UINT global_interface_index, VOID *dynamic_cache_memory, UINT dynamic_cache_size)
228 {
229
230 UINT i;
231 UINT dynamic_entries;
232 NX_NAT_TRANSLATION_ENTRY *entry_ptr;
233
234
235 /* First clear memory for setting up the NAT server instance. */
236 memset(nat_ptr, 0, sizeof(NX_NAT_DEVICE));
237
238 /* Bind the IP instance and related parameters. */
239 nat_ptr -> nx_nat_ip_ptr = ip_ptr;
240 nat_ptr -> nx_nat_global_interface_index = (UCHAR)global_interface_index;
241
242 /* Clear the entry cache. */
243 memset((void *) dynamic_cache_memory, 0, dynamic_cache_size);
244
245 /* Pickup starting address of the available entry list. */
246 entry_ptr = (NX_NAT_TRANSLATION_ENTRY *) dynamic_cache_memory;
247
248 /* Determine how many NAT daynamic entries will fit in this cache area. */
249 dynamic_entries = dynamic_cache_size / sizeof(NX_NAT_TRANSLATION_ENTRY);
250
251 /* Initialize the pointers of available NAT entries. */
252 for (i = 0; i < (dynamic_entries - 1); i++)
253 {
254 /* Setup each entry to point to the next entry. */
255 entry_ptr -> next_entry_ptr = entry_ptr + 1;
256 entry_ptr ++;
257 }
258
259 /* Setup the head pointers of the available and dynamic (active) lists in the NAT Device. */
260 nat_ptr -> nx_nat_dynamic_available_entry_head = (NX_NAT_TRANSLATION_ENTRY *) dynamic_cache_memory;
261 nat_ptr -> nx_nat_dynamic_active_entry_head = NX_NULL;
262 nat_ptr -> nx_nat_dynamic_available_entries = dynamic_entries;
263 nat_ptr -> nx_nat_dynamic_active_entries = 0;
264 nat_ptr -> nx_nat_static_active_entries = 0;
265
266 /* Load the NAT ID field in the NAT control block. */
267 nat_ptr -> nx_nat_id = NX_NAT_ID;
268
269 /* Define a global NAT pointer. NetX forwards all packets to _nx_nat_process_packet if _nx_ip_packet_forward() is defined as such.
270 The latter service can only send the current NX_IP and NX_PACKET pointer, so _nx_nat_process_packet()
271 requries this global pointer. */
272 /* Set the pointer of global variable NAT. */
273 nat_server_ptr = nat_ptr;
274
275 /* Return successful completion. */
276 return NX_SUCCESS;
277 }
278
279
280 /**************************************************************************/
281 /* */
282 /* FUNCTION RELEASE */
283 /* */
284 /* _nxe_nat_delete PORTABLE C */
285 /* 6.1 */
286 /* AUTHOR */
287 /* */
288 /* Yuxin Zhou, Microsoft Corporation */
289 /* */
290 /* DESCRIPTION */
291 /* */
292 /* This function performs error checking on the delete NAT service. */
293 /* */
294 /* INPUT */
295 /* */
296 /* nat_ptr Pointer to NAT instance */
297 /* */
298 /* OUTPUT */
299 /* */
300 /* NX_PTR_ERROR Invalid pointer parameter */
301 /* status Actual completion status */
302 /* */
303 /* CALLS */
304 /* */
305 /* _nx_nat_delete Deletes a NAT instance */
306 /* */
307 /* CALLED BY */
308 /* */
309 /* Application Code */
310 /* */
311 /* RELEASE HISTORY */
312 /* */
313 /* DATE NAME DESCRIPTION */
314 /* */
315 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
316 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
317 /* resulting in version 6.1 */
318 /* */
319 /**************************************************************************/
_nxe_nat_delete(NX_NAT_DEVICE * nat_ptr)320 UINT _nxe_nat_delete(NX_NAT_DEVICE *nat_ptr)
321 {
322
323 UINT status;
324
325
326 /* Check for invalid input pointers. */
327 if ((nat_ptr == NX_NULL) || (nat_ptr -> nx_nat_id != NX_NAT_ID))
328 return(NX_PTR_ERROR);
329
330 /* Check for appropriate caller. */
331 NX_THREADS_ONLY_CALLER_CHECKING
332
333 /* Call the actual NAT delete service. */
334 status = _nx_nat_delete(nat_ptr);
335
336 /* Return completion status. */
337 return(status);
338 }
339
340
341 /**************************************************************************/
342 /* */
343 /* FUNCTION RELEASE */
344 /* */
345 /* _nx_nat_delete PORTABLE C */
346 /* 6.1 */
347 /* AUTHOR */
348 /* */
349 /* Yuxin Zhou, Microsoft Corporation */
350 /* */
351 /* DESCRIPTION */
352 /* */
353 /* This function deletes the specified NetX NAT instance. */
354 /* */
355 /* INPUT */
356 /* */
357 /* nat_ptr Pointer to NAT server to delete */
358 /* */
359 /* OUTPUT */
360 /* */
361 /* status Actual completion status */
362 /* */
363 /* CALLS */
364 /* */
365 /* tx_mutex_delete Delete NAT mutex */
366 /* */
367 /* CALLED BY */
368 /* */
369 /* Application code */
370 /* */
371 /* RELEASE HISTORY */
372 /* */
373 /* DATE NAME DESCRIPTION */
374 /* */
375 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
376 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
377 /* resulting in version 6.1 */
378 /* */
379 /**************************************************************************/
_nx_nat_delete(NX_NAT_DEVICE * nat_ptr)380 UINT _nx_nat_delete(NX_NAT_DEVICE *nat_ptr)
381 {
382
383 /* Clear the NAT ID to make it invalid. */
384 nat_ptr -> nx_nat_id = 0;
385
386 return NX_SUCCESS;
387 }
388
389
390 /**************************************************************************/
391 /* */
392 /* FUNCTION RELEASE */
393 /* */
394 /* _nxe_nat_enable PORTABLE C */
395 /* 6.1 */
396 /* AUTHOR */
397 /* */
398 /* Yuxin Zhou, Microsoft Corporation */
399 /* */
400 /* DESCRIPTION */
401 /* */
402 /* This function performs error checking on the resume NAT thread */
403 /* service. */
404 /* */
405 /* INPUT */
406 /* */
407 /* ip_ptr Pointer to IP instance */
408 /* */
409 /* OUTPUT */
410 /* */
411 /* status Actual completion status */
412 /* NX_PTR_ERROR Invalid pointer parameter */
413 /* */
414 /* CALLS */
415 /* */
416 /* _nx_nat_enable Actual enable NAT server */
417 /* */
418 /* CALLED BY */
419 /* */
420 /* Application code */
421 /* */
422 /* RELEASE HISTORY */
423 /* */
424 /* DATE NAME DESCRIPTION */
425 /* */
426 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
427 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
428 /* resulting in version 6.1 */
429 /* */
430 /**************************************************************************/
_nxe_nat_enable(NX_NAT_DEVICE * nat_ptr)431 UINT _nxe_nat_enable(NX_NAT_DEVICE *nat_ptr)
432 {
433
434 UINT status;
435
436 /* Check for invalid input pointers. */
437 if ((nat_ptr == NX_NULL) || (nat_ptr -> nx_nat_id != NX_NAT_ID))
438 return(NX_PTR_ERROR);
439
440 /* Call the actual service. */
441 status = _nx_nat_enable(nat_ptr);
442
443 /* Return completion status. */
444 return status;
445 }
446
447
448 /**************************************************************************/
449 /* */
450 /* FUNCTION RELEASE */
451 /* */
452 /* _nx_nat_enable PORTABLE C */
453 /* 6.1 */
454 /* AUTHOR */
455 /* */
456 /* Yuxin Zhou, Microsoft Corporation */
457 /* */
458 /* DESCRIPTION */
459 /* */
460 /* This function enables the NAT server. */
461 /* */
462 /* INPUT */
463 /* */
464 /* nat_ptr Pointer to NAT server to resume */
465 /* */
466 /* OUTPUT */
467 /* */
468 /* NX_SUCCESS Successful completion status */
469 /* */
470 /* CALLS */
471 /* */
472 /* tx_mutex_get Get IP mutex */
473 /* tx_mutex_put Put IP mutex */
474 /* */
475 /* CALLED BY */
476 /* */
477 /* Application code */
478 /* */
479 /* RELEASE HISTORY */
480 /* */
481 /* DATE NAME DESCRIPTION */
482 /* */
483 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
484 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
485 /* resulting in version 6.1 */
486 /* */
487 /**************************************************************************/
_nx_nat_enable(NX_NAT_DEVICE * nat_ptr)488 UINT _nx_nat_enable(NX_NAT_DEVICE *nat_ptr)
489 {
490
491
492 /* Get the IP mutex. */
493 tx_mutex_get(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
494
495 /* Setup the IP nat processing routine pointer for NAT services. */
496 nat_ptr -> nx_nat_ip_ptr -> nx_ip_nat_packet_process = _nx_nat_process_packet;
497
498 /* Setup the IP nat free port check for NAT services. */
499 nat_ptr -> nx_nat_ip_ptr -> nx_ip_nat_port_verify = _nx_nat_entry_port_verify;
500
501 /* Release the IP mutex. */
502 tx_mutex_put(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection));
503
504 /* Return successful completion. */
505 return(NX_SUCCESS);
506 }
507
508
509 /**************************************************************************/
510 /* */
511 /* FUNCTION RELEASE */
512 /* */
513 /* _nxe_nat_disable PORTABLE C */
514 /* 6.1 */
515 /* AUTHOR */
516 /* */
517 /* Yuxin Zhou, Microsoft Corporation */
518 /* */
519 /* DESCRIPTION */
520 /* */
521 /* This function performs error checking on the disable NAT service. */
522 /* INPUT */
523 /* */
524 /* nat_ptr Pointer to NAT instance */
525 /* */
526 /* OUTPUT */
527 /* */
528 /* status Actual completion status */
529 /* NX_PTR_ERROR Invalid pointer parameter */
530 /* */
531 /* CALLS */
532 /* */
533 /* _nx_nat_enable Actual enable NAT server */
534 /* */
535 /* CALLED BY */
536 /* */
537 /* Application code */
538 /* */
539 /* RELEASE HISTORY */
540 /* */
541 /* DATE NAME DESCRIPTION */
542 /* */
543 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
544 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
545 /* resulting in version 6.1 */
546 /* */
547 /**************************************************************************/
_nxe_nat_disable(NX_NAT_DEVICE * nat_ptr)548 UINT _nxe_nat_disable(NX_NAT_DEVICE *nat_ptr)
549 {
550
551 UINT status;
552
553
554 /* Check for invalid input pointers. */
555 if ((nat_ptr == NX_NULL) || (nat_ptr -> nx_nat_id != NX_NAT_ID))
556 return(NX_PTR_ERROR);
557
558 /* Call the actual service. */
559 status = _nx_nat_disable(nat_ptr);
560
561 /* Return completion status. */
562 return status;
563 }
564
565
566 /**************************************************************************/
567 /* */
568 /* FUNCTION RELEASE */
569 /* */
570 /* _nx_nat_disable PORTABLE C */
571 /* 6.1 */
572 /* AUTHOR */
573 /* */
574 /* Yuxin Zhou, Microsoft Corporation */
575 /* */
576 /* DESCRIPTION */
577 /* */
578 /* This function disables the NAT server. */
579 /* */
580 /* INPUT */
581 /* */
582 /* nat_ptr Pointer to NAT server to resume */
583 /* */
584 /* OUTPUT */
585 /* */
586 /* NX_SUCCESS Successful completion status */
587 /* */
588 /* CALLS */
589 /* */
590 /* tx_mutex_get Get IP mutex */
591 /* tx_mutex_put Put IP mutex */
592 /* */
593 /* CALLED BY */
594 /* */
595 /* Application code */
596 /* */
597 /* RELEASE HISTORY */
598 /* */
599 /* DATE NAME DESCRIPTION */
600 /* */
601 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
602 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
603 /* resulting in version 6.1 */
604 /* */
605 /**************************************************************************/
_nx_nat_disable(NX_NAT_DEVICE * nat_ptr)606 UINT _nx_nat_disable(NX_NAT_DEVICE *nat_ptr)
607 {
608
609 /* Get the IP mutex. */
610 tx_mutex_get(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
611
612 /* Clear the IP nat processing routine pointer. */
613 nat_ptr -> nx_nat_ip_ptr -> nx_ip_nat_packet_process = NX_NULL;
614
615 /* Release the IP mutex. */
616 tx_mutex_put(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection));
617
618 /* Return successful completion. */
619 return(NX_SUCCESS);
620 }
621
622
623 /**************************************************************************/
624 /* */
625 /* FUNCTION RELEASE */
626 /* */
627 /* _nxe_nat_cache_notify_set PORTABLE C */
628 /* 6.1 */
629 /* AUTHOR */
630 /* */
631 /* Yuxin Zhou, Microsoft Corporation */
632 /* */
633 /* DESCRIPTION */
634 /* */
635 /* This function checks for errors in the NAT cache full notify */
636 /* function call. */
637 /* */
638 /* INPUT */
639 /* */
640 /* nat_ptr Pointer to NAT instance */
641 /* cache_full_notify Cache full notify function */
642 /* */
643 /* OUTPUT */
644 /* */
645 /* status Completion status */
646 /* */
647 /* CALLS */
648 /* */
649 /* _nx_nat_cache_notify_set Actual cache notify set function */
650 /* */
651 /* CALLED BY */
652 /* */
653 /* Application Code */
654 /* */
655 /* RELEASE HISTORY */
656 /* */
657 /* DATE NAME DESCRIPTION */
658 /* */
659 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
660 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
661 /* resulting in version 6.1 */
662 /* */
663 /**************************************************************************/
_nxe_nat_cache_notify_set(NX_NAT_DEVICE * nat_ptr,VOID (* cache_full_notify_cb)(NX_NAT_DEVICE * nat_ptr))664 UINT _nxe_nat_cache_notify_set(NX_NAT_DEVICE *nat_ptr, VOID (*cache_full_notify_cb)(NX_NAT_DEVICE *nat_ptr))
665 {
666
667 UINT status;
668
669
670 /* Check for invalid input pointers. */
671 if (!nat_ptr)
672 {
673 return(NX_PTR_ERROR);
674 }
675
676 /* Check for invalid non pointer input. */
677 if (nat_ptr -> nx_nat_id != NX_NAT_ID)
678 {
679 return(NX_NAT_PARAM_ERROR);
680 }
681
682 /* Call actual NAT cache notify set function. */
683 status = _nx_nat_cache_notify_set(nat_ptr, cache_full_notify_cb);
684
685 /* Return status. */
686 return(status);
687 }
688
689
690 /**************************************************************************/
691 /* */
692 /* FUNCTION RELEASE */
693 /* */
694 /* _nx_nat_cache_notify_set PORTABLE C */
695 /* 6.1 */
696 /* AUTHOR */
697 /* */
698 /* Yuxin Zhou, Microsoft Corporation */
699 /* */
700 /* DESCRIPTION */
701 /* */
702 /* This function set the cache full notify function. */
703 /* */
704 /* INPUT */
705 /* */
706 /* nat_ptr Pointer to nat instance */
707 /* cache_full_notify Cache full notify function */
708 /* */
709 /* OUTPUT */
710 /* */
711 /* status Completion status */
712 /* */
713 /* CALLS */
714 /* */
715 /* tx_mutex_get Get IP mutex */
716 /* tx_mutex_put Put IP mutex */
717 /* */
718 /* CALLED BY */
719 /* */
720 /* Application Code */
721 /* */
722 /* RELEASE HISTORY */
723 /* */
724 /* DATE NAME DESCRIPTION */
725 /* */
726 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
727 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
728 /* resulting in version 6.1 */
729 /* */
730 /**************************************************************************/
_nx_nat_cache_notify_set(NX_NAT_DEVICE * nat_ptr,VOID (* cache_full_notify_cb)(NX_NAT_DEVICE * nat_ptr))731 UINT _nx_nat_cache_notify_set(NX_NAT_DEVICE *nat_ptr, VOID (*cache_full_notify_cb)(NX_NAT_DEVICE *nat_ptr))
732 {
733
734
735 /* Get the IP mutex. */
736 tx_mutex_get(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
737
738 /* Set the cache notify. */
739 nat_ptr -> nx_nat_cache_full_notify = cache_full_notify_cb;
740
741 /* Release the IP mutex. */
742 tx_mutex_put(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection));
743
744 return(NX_SUCCESS);
745 }
746
747 /**************************************************************************/
748 /* */
749 /* FUNCTION RELEASE */
750 /* */
751 /* _nxe_nat_inbound_entry_create PORTABLE C */
752 /* 6.1 */
753 /* AUTHOR */
754 /* */
755 /* Yuxin Zhou, Microsoft Corporation */
756 /* */
757 /* DESCRIPTION */
758 /* */
759 /* This function performs error checking on the create NAT translation */
760 /* inbound entry service. */
761 /* */
762 /* INPUT */
763 /* */
764 /* nat_ptr Pointer to NAT instance */
765 /* entry_ptr Pointer to entry to add to table */
766 /* local_ip_address Entry local IP address */
767 /* external_port Entry external port */
768 /* local_port Entry local port */
769 /* protocol Entry network protocol */
770 /* */
771 /* OUTPUT */
772 /* */
773 /* NX_PTR_ERROR Invalid pointer parameter */
774 /* NX_NAT_PARAM_ERROR Invalid non pointer parameter */
775 /* status Actual completion status */
776 /* */
777 /* CALLS */
778 /* */
779 /* _nx_nat_inbound_entry_create Calls actual create entry service */
780 /* */
781 /* CALLED BY */
782 /* */
783 /* Application code */
784 /* */
785 /* RELEASE HISTORY */
786 /* */
787 /* DATE NAME DESCRIPTION */
788 /* */
789 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
790 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
791 /* resulting in version 6.1 */
792 /* */
793 /**************************************************************************/
_nxe_nat_inbound_entry_create(NX_NAT_DEVICE * nat_ptr,NX_NAT_TRANSLATION_ENTRY * entry_ptr,ULONG local_ip_address,USHORT external_port,USHORT local_port,UCHAR protocol)794 UINT _nxe_nat_inbound_entry_create(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr,
795 ULONG local_ip_address, USHORT external_port, USHORT local_port, UCHAR protocol)
796 {
797
798 UINT status;
799
800
801 /* Check for invalid input pointers. */
802 if ((nat_ptr == NX_NULL) || (nat_ptr -> nx_nat_id != NX_NAT_ID) || (!entry_ptr))
803 {
804 return (NX_PTR_ERROR);
805 }
806
807 /* Check for invalid non pointer input. */
808 if ((!local_ip_address) || (!protocol))
809 {
810
811 /* Return ptr error. */
812 return (NX_NAT_PARAM_ERROR);
813 }
814
815 /* Call the actual service. */
816 status = _nx_nat_inbound_entry_create(nat_ptr, entry_ptr, local_ip_address, external_port, local_port, protocol);
817
818 /* Return completion status. */
819 return status;
820 }
821
822
823 /**************************************************************************/
824 /* */
825 /* FUNCTION RELEASE */
826 /* */
827 /* _nx_nat_inbound_entry_create PORTABLE C */
828 /* 6.1 */
829 /* AUTHOR */
830 /* */
831 /* Yuxin Zhou, Microsoft Corporation */
832 /* */
833 /* DESCRIPTION */
834 /* */
835 /* This function creates a inbound NAT translation entry and adds it to */
836 /* the NAT entry list. This is allows an external host to initiate */
837 /* a session with a private host (typically a server). */
838 /* */
839 /* This entry can never expire. To remove the entry, use the */
840 /* nx_nat_inbound_entry_delete() service. */
841 /* */
842 /* INPUT */
843 /* */
844 /* nat_ptr Pointer to NAT instance */
845 /* entry_ptr Pointer to entry to add to table */
846 /* local_ip_address Entry local IP address */
847 /* external_port Entry external port */
848 /* local_port Entry local port */
849 /* protocol Table entry network protocol */
850 /* */
851 /* OUTPUT */
852 /* */
853 /* NX_SUCCESS Successful completion status */
854 /* */
855 /* CALLS */
856 /* */
857 /* tx_mutex_get Get IP mutex */
858 /* tx_mutex_put Put IP mutex */
859 /* _nx_nat_entry_add Add entry to table linked list */
860 /* memset Clear specified area of memory */
861 /* */
862 /* CALLED BY */
863 /* */
864 /* Application code */
865 /* */
866 /* RELEASE HISTORY */
867 /* */
868 /* DATE NAME DESCRIPTION */
869 /* */
870 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
871 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
872 /* resulting in version 6.1 */
873 /* */
874 /**************************************************************************/
_nx_nat_inbound_entry_create(NX_NAT_DEVICE * nat_ptr,NX_NAT_TRANSLATION_ENTRY * entry_ptr,ULONG local_ip_address,USHORT external_port,USHORT local_port,UCHAR protocol)875 UINT _nx_nat_inbound_entry_create(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr,
876 ULONG local_ip_address, USHORT external_port, USHORT local_port, UCHAR protocol)
877 {
878
879 UINT bound;
880
881 /* Get the IP mutex. */
882 tx_mutex_get(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
883
884 /* Check whether this port has been used by NAT entry. */
885 bound = _nx_nat_entry_port_verify(nat_ptr -> nx_nat_ip_ptr, protocol, external_port);
886
887 /* Check the status. */
888 if (bound == NX_TRUE)
889 {
890
891 /* Release the IP mutex. */
892 tx_mutex_put(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection));
893
894 /* Return error status. */
895 return(NX_NAT_PORT_UNAVAILABLE);
896 }
897
898 /* Check whether this port has been used by NetXDuo socket. */
899 bound = _nx_nat_socket_port_verify(nat_ptr -> nx_nat_ip_ptr, protocol, external_port);
900
901 /* Check the status. */
902 if (bound == NX_TRUE)
903 {
904
905 /* Release the IP mutex. */
906 tx_mutex_put(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection));
907
908 /* Return error status. */
909 return(NX_NAT_PORT_UNAVAILABLE);
910 }
911
912 /* Initialize the entry to NULL. */
913 memset(entry_ptr, 0, sizeof(NX_NAT_TRANSLATION_ENTRY));
914
915 /* Assign the entry attributes. */
916 entry_ptr -> local_ip_address = local_ip_address;
917 entry_ptr -> external_port = external_port;
918 entry_ptr -> local_port = local_port;
919 entry_ptr -> protocol = protocol;
920
921 /* Set the transaction type. */
922 entry_ptr -> translation_type = NX_NAT_STATIC_ENTRY;
923
924 /* Add the entry to the table. */
925 _nx_nat_entry_add(nat_ptr, entry_ptr);
926
927 /* Release the IP mutex. */
928 tx_mutex_put(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection));
929
930 /* Return successful completion status. */
931 return NX_SUCCESS;
932 }
933
934
935 /**************************************************************************/
936 /* */
937 /* FUNCTION RELEASE */
938 /* */
939 /* _nxe_nat_inbound_entry_delete PORTABLE C */
940 /* 6.1 */
941 /* AUTHOR */
942 /* */
943 /* Yuxin Zhou, Microsoft Corporation */
944 /* */
945 /* DESCRIPTION */
946 /* */
947 /* This function performs error checking on the delete NAT translation */
948 /* inbound entry service. */
949 /* */
950 /* INPUT */
951 /* */
952 /* nat_ptr Pointer to NAT instance */
953 /* remove_entry_ptr Pointer to NAT translation entry */
954 /* */
955 /* OUTPUT */
956 /* */
957 /* status Actual completion status */
958 /* NX_PTR_ERROR Invalid pointer parameter */
959 /* */
960 /* CALLS */
961 /* */
962 /* _nx_nat_inbound_entry_delete Actual table entry delete service */
963 /* */
964 /* CALLED BY */
965 /* */
966 /* Application code */
967 /* */
968 /* RELEASE HISTORY */
969 /* */
970 /* DATE NAME DESCRIPTION */
971 /* */
972 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
973 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
974 /* resulting in version 6.1 */
975 /* */
976 /**************************************************************************/
_nxe_nat_inbound_entry_delete(NX_NAT_DEVICE * nat_ptr,NX_NAT_TRANSLATION_ENTRY * delete_entry_ptr)977 UINT _nxe_nat_inbound_entry_delete( NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *delete_entry_ptr)
978 {
979
980 UINT status;
981
982 /* Check for invalid input pointers. */
983 if ((nat_ptr == NX_NULL) || (nat_ptr -> nx_nat_id != NX_NAT_ID) || (delete_entry_ptr == NX_NULL))
984 {
985
986 return(NX_PTR_ERROR);
987 }
988
989 /* Check the entry tranlation type. */
990 if (delete_entry_ptr ->translation_type != NX_NAT_STATIC_ENTRY)
991 {
992 return(NX_NAT_ENTRY_TYPE_ERROR);
993 }
994
995 /* Check if this function is called from the appropriate thread. */
996 NX_THREADS_ONLY_CALLER_CHECKING
997
998 /* Call the actual NAT entry delete service. */
999 status = _nx_nat_inbound_entry_delete(nat_ptr, delete_entry_ptr);
1000
1001 /* Return completion status. */
1002 return(status);
1003 }
1004
1005
1006 /**************************************************************************/
1007 /* */
1008 /* FUNCTION RELEASE */
1009 /* */
1010 /* _nx_nat_inbound_entry_delete PORTABLE C */
1011 /* 6.1 */
1012 /* AUTHOR */
1013 /* */
1014 /* Yuxin Zhou, Microsoft Corporation */
1015 /* */
1016 /* DESCRIPTION */
1017 /* */
1018 /* This function deletes the specified static entry from the NAT */
1019 /* translation list. */
1020 /* */
1021 /* INPUT */
1022 /* */
1023 /* nat_ptr Pointer to NAT instance */
1024 /* remove_entry_ptr Pointer to NAT translation entry */
1025 /* */
1026 /* OUTPUT */
1027 /* */
1028 /* status Actual completion status */
1029 /* */
1030 /* CALLS */
1031 /* */
1032 /* memset Clear specified area of memory */
1033 /* */
1034 /* CALLED BY */
1035 /* */
1036 /* Application code */
1037 /* */
1038 /* RELEASE HISTORY */
1039 /* */
1040 /* DATE NAME DESCRIPTION */
1041 /* */
1042 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1043 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1044 /* resulting in version 6.1 */
1045 /* */
1046 /**************************************************************************/
_nx_nat_inbound_entry_delete(NX_NAT_DEVICE * nat_ptr,NX_NAT_TRANSLATION_ENTRY * delete_entry_ptr)1047 UINT _nx_nat_inbound_entry_delete(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *delete_entry_ptr)
1048 {
1049
1050 NX_NAT_TRANSLATION_ENTRY *entry_ptr;
1051 NX_NAT_TRANSLATION_ENTRY *previous_ptr;
1052 NX_NAT_TRANSLATION_ENTRY *next_entry_ptr;
1053
1054
1055 /* Get the IP mutex. */
1056 tx_mutex_get(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
1057
1058 /* Get a pointer to the start of the entries in the translation table. */
1059 entry_ptr = nat_ptr -> nx_nat_dynamic_active_entry_head;
1060
1061 /* Initialize the previous pointer. */
1062 previous_ptr = NX_NULL;
1063
1064 /* We need to loop through the translation table again so we
1065 can remove the entry to delete and connect the previous and
1066 next entries around it. */
1067 while (entry_ptr)
1068 {
1069
1070 /* Set a pointer to the next entry in the table. */
1071 next_entry_ptr = entry_ptr -> next_entry_ptr;
1072
1073 /* Is this the entry we want to delete? */
1074 if (entry_ptr == delete_entry_ptr)
1075 {
1076
1077 /* Yes; check if this is the first entry in the list). */
1078 if (previous_ptr)
1079 {
1080
1081 /* It is not, so link the previous entry around the entry we are deleting. */
1082 previous_ptr -> next_entry_ptr = next_entry_ptr;
1083 }
1084 else
1085 {
1086
1087 /* It is the first entry, so set the next pointer as the starting translation table entry. */
1088 nat_ptr -> nx_nat_dynamic_active_entry_head = next_entry_ptr;
1089 }
1090
1091 /* Update the static active entry count. */
1092 nat_ptr -> nx_nat_static_active_entries --;
1093
1094 /* Release the IP mutex. */
1095 tx_mutex_put(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection));
1096
1097 /* We're done here. */
1098 return NX_SUCCESS;
1099 }
1100
1101 /* We didn't delete the current entry, so now it is the previous entry. */
1102 previous_ptr = entry_ptr;
1103
1104 /* Get the next entry in the table. */
1105 entry_ptr = next_entry_ptr;
1106 }
1107
1108 /* Release the IP mutex. */
1109 tx_mutex_put(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection));
1110
1111 /* Return error status. */
1112 return (NX_NAT_ENTRY_NOT_FOUND);
1113 }
1114
1115
1116 /**************************************************************************/
1117 /* */
1118 /* FUNCTION RELEASE */
1119 /* */
1120 /* _nx_nat_process_packet PORTABLE C */
1121 /* 6.3.0 */
1122 /* AUTHOR */
1123 /* */
1124 /* Yuxin Zhou, Microsoft Corporation */
1125 /* */
1126 /* DESCRIPTION */
1127 /* */
1128 /* This function receives packets to forward from both public and */
1129 /* private networks on either side of NAT if IP forwarding is enabled */
1130 /* and this function is specified as the packet handler. It determines */
1131 /* packet direction (e.g. out to the public internet or inbound to a */
1132 /* host on the private network) and forwards it to the appropriate */
1133 /* handler. */
1134 /* */
1135 /* INPUT */
1136 /* */
1137 /* ip_ptr Pointer to IP instance */
1138 /* packet_ptr Pointer to packet to forward */
1139 /* packet_process The flag for packet processing */
1140 /* NX_TRUE or NX_FALSE */
1141 /* */
1142 /* OUTPUT */
1143 /* */
1144 /* NX_TRUE Packet is consumed by NAT */
1145 /* NX_FALSE Packet is not consumed by NAT */
1146 /* */
1147 /* CALLS */
1148 /* */
1149 /* nx_packet_release Release the packet */
1150 /* _nx_ip_route_find Find the outgoing interface */
1151 /* _nx_nat_process_outbound_packet Forward packet to public Internet */
1152 /* _nx_nat_process_inbound_packet Forward packet to private host */
1153 /* */
1154 /* CALLED BY */
1155 /* */
1156 /* _nx_ipv4_packet_receive NetX forwards packet to NAT first */
1157 /* if forwarding is enabled. */
1158 /* */
1159 /* RELEASE HISTORY */
1160 /* */
1161 /* DATE NAME DESCRIPTION */
1162 /* */
1163 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1164 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1165 /* resulting in version 6.1 */
1166 /* 10-31-2023 Tiejun Zhou Modified comment(s), */
1167 /* fixed packet double release,*/
1168 /* resulting in version 6.3.0 */
1169 /* */
1170 /**************************************************************************/
_nx_nat_process_packet(NX_IP * ip_ptr,NX_PACKET * packet_ptr,UINT packet_process)1171 static UINT _nx_nat_process_packet(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT packet_process)
1172 {
1173
1174 UINT status;
1175 UINT protocol;
1176 ULONG header_size = sizeof(NX_IPV4_HEADER);
1177 UINT global_interface_index;
1178 ULONG next_hop_address;
1179 NX_IPV4_HEADER *ip_header_ptr;
1180 NX_INTERFACE *interface_ptr;
1181
1182
1183 /* Check the NAT's IP instance. */
1184 if (nat_server_ptr -> nx_nat_ip_ptr != ip_ptr)
1185 {
1186
1187 /* Let IP packet receive process this packet. */
1188 return (NX_FALSE);
1189 }
1190
1191 /* Pickup the packet header. */
1192 ip_header_ptr = (NX_IPV4_HEADER *) packet_ptr -> nx_packet_prepend_ptr;
1193
1194 /* Determine what protocol the current IP datagram is. */
1195 protocol = (ip_header_ptr -> nx_ip_header_word_2 >> 16) & 0xFF;
1196
1197 /* Check the protocol. */
1198 if ((protocol != NX_PROTOCOL_ICMP) && (protocol != NX_PROTOCOL_UDP) && (protocol != NX_PROTOCOL_TCP))
1199 {
1200
1201 /* Let IP packet receive process this packet. */
1202 return (NX_FALSE);
1203 }
1204
1205 #ifndef NX_DISABLE_RX_SIZE_CHECKING
1206 /* Check the next protocol. */
1207 if (protocol == NX_PROTOCOL_ICMP)
1208 {
1209 header_size += sizeof(NX_ICMP_HEADER);
1210 }
1211 else if (protocol == NX_PROTOCOL_UDP)
1212 {
1213 header_size += sizeof(NX_UDP_HEADER);
1214 }
1215 else
1216 {
1217 header_size += sizeof(NX_TCP_HEADER);
1218 }
1219
1220 /* Check for valid packet length. */
1221 if (packet_ptr -> nx_packet_length < header_size)
1222 {
1223 if (packet_process == NX_TRUE)
1224 {
1225 #ifndef NX_DISABLE_IP_INFO
1226 /* Increment the IP invalid packet error. */
1227 ip_ptr -> nx_ip_invalid_packets++;
1228
1229 /* Increment the IP receive packets dropped count. */
1230 ip_ptr -> nx_ip_receive_packets_dropped++;
1231 #endif
1232
1233 /* Invalid packet length, just release it. */
1234 _nx_packet_release(packet_ptr);
1235 }
1236
1237 /* Return NX_TRUE to indicate this packet has been processed. */
1238 return (NX_TRUE);
1239 }
1240 #endif /* NX_DISABLE_RX_SIZE_CHECKING */
1241
1242 /* Set the packet interface pointer and NAT's global interface index. */
1243 interface_ptr = packet_ptr -> nx_packet_address.nx_packet_interface_ptr;
1244 global_interface_index = nat_server_ptr -> nx_nat_global_interface_index;
1245
1246 /* Check if the direction of the translation is inbound. */
1247 if (interface_ptr == &(ip_ptr -> nx_ip_interface[global_interface_index]))
1248 {
1249
1250 /* Yes, this packet is received on NAT's external interface (an inbound packet). */
1251
1252 /* Check the destination ip address against NAT's external IP address. */
1253 if (ip_header_ptr -> nx_ip_header_destination_ip != interface_ptr -> nx_interface_ip_address)
1254 {
1255
1256 /* NAT cannot process this packet. Let IP packet receive process this packet. */
1257 return (NX_FALSE);
1258 }
1259
1260 /* Check if the caller wants NAT to process this packet. */
1261 if (packet_process == NX_TRUE)
1262 {
1263
1264 #ifndef NX_DISABLE_NAT_INFO
1265 /* Yes, so update the count. */
1266 nat_server_ptr -> forwarded_packets_received ++;
1267 #endif
1268
1269 /* Try to deliver the packet to the local host. */
1270 status = _nx_nat_process_inbound_packet(nat_server_ptr, packet_ptr);
1271
1272 /* Check the status. */
1273 if (status == NX_NAT_PACKET_CONSUMED_FAILED)
1274 {
1275
1276 /* Let IP packet receive process this packet. */
1277 return (NX_FALSE);
1278 }
1279 }
1280 }
1281 else
1282 {
1283
1284 /* Check the destination ip address. */
1285 if (
1286
1287 /* Check for zero address. */
1288 (ip_header_ptr -> nx_ip_header_destination_ip == 0) ||
1289
1290 /* Check for limited broadcast. */
1291 (ip_header_ptr -> nx_ip_header_destination_ip == NX_IP_LIMITED_BROADCAST) ||
1292
1293 /* Check for multicast address*/
1294 ((ip_header_ptr -> nx_ip_header_destination_ip & NX_IP_CLASS_D_MASK) == NX_IP_CLASS_D_TYPE) ||
1295
1296 /* Check for loopback address. */
1297 ((ip_header_ptr -> nx_ip_header_destination_ip >= NX_IP_LOOPBACK_FIRST) &&
1298 (ip_header_ptr -> nx_ip_header_destination_ip <= NX_IP_LOOPBACK_LAST)))
1299 {
1300
1301 /* Let IP packet receive process this packet. */
1302 return (NX_FALSE);
1303 }
1304
1305 /* Clear the packet interface. */
1306 interface_ptr = NX_NULL;
1307
1308 /* Find the suitable interface and next hop address according to the destination ip. */
1309 if(_nx_ip_route_find(ip_ptr, ip_header_ptr -> nx_ip_header_destination_ip, &interface_ptr, &next_hop_address) != NX_SUCCESS)
1310 {
1311
1312 /* Let IP packet receive process this packet. */
1313 return (NX_FALSE);
1314 }
1315
1316 /* Check the NAT forward interface. */
1317 if (interface_ptr != &(ip_ptr -> nx_ip_interface[global_interface_index]))
1318 {
1319
1320 /* Let IP packet receive process this packet. */
1321 return (NX_FALSE);
1322 }
1323
1324 /* Check for IP broadcast. */
1325 if(((ip_header_ptr -> nx_ip_header_destination_ip & interface_ptr -> nx_interface_ip_network_mask) ==
1326 interface_ptr -> nx_interface_ip_network) &&
1327 ((ip_header_ptr -> nx_ip_header_destination_ip & ~(interface_ptr -> nx_interface_ip_network_mask)) ==
1328 ~(interface_ptr -> nx_interface_ip_network_mask)))
1329 {
1330
1331 /* Let IP packet receive process this packet. */
1332 return (NX_FALSE);
1333 }
1334
1335 /* Check if NAT need to process this packet. */
1336 if (packet_process == NX_TRUE)
1337 {
1338
1339 /* Set the packet interface as global interface. */
1340 packet_ptr -> nx_packet_address.nx_packet_interface_ptr = interface_ptr;
1341
1342 #ifndef NX_DISABLE_NAT_INFO
1343 /* Update the count. */
1344 nat_server_ptr -> forwarded_packets_received ++;
1345 #endif
1346
1347 /* Deliver the packet to the outbound packet handler. */
1348 _nx_nat_process_outbound_packet(nat_server_ptr, packet_ptr);
1349 }
1350 }
1351
1352 /* Return NX_TRUE to indicate packet has been processed by NAT. */
1353 return (NX_TRUE);
1354 }
1355
1356
1357 /**************************************************************************/
1358 /* */
1359 /* FUNCTION RELEASE */
1360 /* */
1361 /* _nx_nat_process_inbound_packet PORTABLE C */
1362 /* 6.1 */
1363 /* AUTHOR */
1364 /* */
1365 /* Yuxin Zhou, Microsoft Corporation */
1366 /* */
1367 /* DESCRIPTION */
1368 /* */
1369 /* This function processes a packet from the external network for */
1370 /* forwarding to the private network. It sends each packet to a */
1371 /* protocol handler for protocol specific processing. */
1372 /* */
1373 /* INPUT */
1374 /* */
1375 /* nat_ptr Pointer to the NAT server */
1376 /* packet_ptr Pointer to the packet to process */
1377 /* */
1378 /* OUTPUT */
1379 /* */
1380 /* status Actual completion status */
1381 /* NX_SUCCESS Successful completion status */
1382 /* NX_NAT_INVALID_PROTOCOL Unknown packet protocol */
1383 /* */
1384 /* CALLS */
1385 /* */
1386 /* _nx_nat_process_inbound_TCP_packet */
1387 /* Process external host's TCP packet */
1388 /* _nx_nat_process_inbound_UDCP_packet */
1389 /* Process external host's UDP packet */
1390 /* _nx_nat_process_inbound_ICMP_packet */
1391 /* Process external host's ICMP packet */
1392 /* nx_packet_release Release the packet */
1393 /* */
1394 /* CALLED BY */
1395 /* */
1396 /* _nx_nat_process_packet Process packet from external host */
1397 /* */
1398 /* RELEASE HISTORY */
1399 /* */
1400 /* DATE NAME DESCRIPTION */
1401 /* */
1402 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1403 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1404 /* resulting in version 6.1 */
1405 /* */
1406 /**************************************************************************/
_nx_nat_process_inbound_packet(NX_NAT_DEVICE * nat_ptr,NX_PACKET * packet_ptr)1407 static UINT _nx_nat_process_inbound_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr)
1408 {
1409
1410
1411 UINT status = NX_SUCCESS;
1412 UCHAR protocol;
1413 NX_IPV4_HEADER *ip_header_ptr;
1414 NX_NAT_TRANSLATION_ENTRY translation_entry;
1415
1416
1417 /* Pick a pointer to the IP header. */
1418 ip_header_ptr = (NX_IPV4_HEADER *) packet_ptr -> nx_packet_prepend_ptr;
1419
1420 /* Determine what protocol the current IP datagram is. */
1421 protocol = (ip_header_ptr -> nx_ip_header_word_2 >> 16) & 0xFF;
1422
1423 /* Set up the search criteria in the NAT translation table. */
1424 memset(&translation_entry, 0, sizeof(NX_NAT_TRANSLATION_ENTRY));
1425 translation_entry.peer_ip_address = ip_header_ptr -> nx_ip_header_source_ip;
1426 translation_entry.protocol = protocol;
1427
1428 /* Choose which packet handler by protocol. */
1429 switch (protocol)
1430 {
1431
1432 case NX_PROTOCOL_TCP:
1433 status = _nx_nat_process_inbound_TCP_packet(nat_ptr, packet_ptr, &translation_entry);
1434 break;
1435
1436 case NX_PROTOCOL_UDP:
1437 status = _nx_nat_process_inbound_UDP_packet(nat_ptr, packet_ptr, &translation_entry);
1438 break;
1439
1440 case NX_PROTOCOL_ICMP:
1441 status = _nx_nat_process_inbound_ICMP_packet(nat_ptr, packet_ptr, &translation_entry);
1442 break;
1443 }
1444
1445 /* Return completion status. */
1446 return status;
1447 }
1448
1449
1450 /**************************************************************************/
1451 /* */
1452 /* FUNCTION RELEASE */
1453 /* */
1454 /* _nx_nat_process_inbound_TCP_packet PORTABLE C */
1455 /* 6.1 */
1456 /* AUTHOR */
1457 /* */
1458 /* Yuxin Zhou, Microsoft Corporation */
1459 /* */
1460 /* DESCRIPTION */
1461 /* */
1462 /* This function finds the local IP address:port for an incoming packet */
1463 /* in the NAT translation table and replaces the global packet */
1464 /* destination IP address and port with the local IP address and port. */
1465 /* If none is found, it rejects the packet. Otherwise it updates the TCP*/
1466 /* checksum with the changed IP address and port. The packet is then */
1467 /* sent to private host. */
1468 /* */
1469 /* INPUT */
1470 /* */
1471 /* nat_ptr Pointer to the NAT server */
1472 /* packet_ptr Pointer to the packet to process */
1473 /* entry_ptr Pointer to the entry */
1474 /* */
1475 /* OUTPUT */
1476 /* */
1477 /* status Actual completion status */
1478 /* NX_SUCCESS Successful completion status */
1479 /* (packet is not necessarily */
1480 /* forwarded) */
1481 /* */
1482 /* CALLS */
1483 /* */
1484 /* _nx_nat_inbound_entry_find Find inbound entry in entry list */
1485 /* _nx_nat_ip_packet_send Send packet to private interface */
1486 /* nx_packet_release Release the packet */
1487 /* */
1488 /* CALLED BY */
1489 /* */
1490 /* _nx_nat_process_inbound_packet Process inbound packets */
1491 /* */
1492 /* RELEASE HISTORY */
1493 /* */
1494 /* DATE NAME DESCRIPTION */
1495 /* */
1496 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1497 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1498 /* resulting in version 6.1 */
1499 /* */
1500 /**************************************************************************/
_nx_nat_process_inbound_TCP_packet(NX_NAT_DEVICE * nat_ptr,NX_PACKET * packet_ptr,NX_NAT_TRANSLATION_ENTRY * entry_ptr)1501 static UINT _nx_nat_process_inbound_TCP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr)
1502 {
1503
1504 UINT status;
1505 UINT entry_found;
1506 USHORT old_port;
1507 USHORT new_port;
1508 ULONG old_address;
1509 ULONG new_address;
1510 USHORT checksum;
1511 ULONG compute_checksum;
1512 ULONG next_hop_address;
1513 NX_TCP_HEADER *tcp_header_ptr;
1514 NX_NAT_TRANSLATION_ENTRY *record_entry;
1515
1516
1517 /* Initialize local variables. */
1518 compute_checksum = 1;
1519 record_entry = NX_NULL;
1520 entry_found = NX_TRUE;
1521
1522 /* Pickup the pointer to the head of the TCP packet. */
1523 packet_ptr -> nx_packet_prepend_ptr += sizeof(NX_IPV4_HEADER);
1524 packet_ptr -> nx_packet_length -= sizeof(NX_IPV4_HEADER);
1525 tcp_header_ptr = (NX_TCP_HEADER *) (packet_ptr -> nx_packet_prepend_ptr);
1526
1527 /* For little endian processors, adjust byte order for big endianness. */
1528 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_0);
1529 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_sequence_number);
1530 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_acknowledgment_number);
1531 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_3);
1532 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_4);
1533
1534 /* Find the inbound entry, set the packet private interface and next hop address. */
1535 status = _nx_nat_inbound_entry_find(nat_ptr, packet_ptr, entry_ptr, &record_entry, &next_hop_address);
1536
1537 /* Check for error. */
1538 if (status != NX_SUCCESS)
1539 {
1540
1541 #ifndef NX_DISABLE_NAT_INFO
1542 /* Update the count. */
1543 nat_ptr -> forwarded_packets_dropped++;
1544 #endif
1545
1546 /* Check the status. */
1547 if (status == NX_NAT_ENTRY_NOT_FOUND)
1548 {
1549
1550 /* Set the entry found flag. */
1551 entry_found = NX_FALSE;
1552 }
1553 else
1554 {
1555
1556 /* Release the packet */
1557 nx_packet_release(packet_ptr);
1558
1559 /* Return completion status. */
1560 return NX_SUCCESS;
1561 }
1562 }
1563 else
1564 {
1565
1566 /* Check the inbound packet destination port, and update the TCP header. */
1567 if (record_entry -> external_port != record_entry -> local_port)
1568 {
1569
1570 /* Replace the destination port with the local (source) port of the preceding outbound packet. */
1571
1572 tcp_header_ptr -> nx_tcp_header_word_0 = ((ULONG)(tcp_header_ptr -> nx_tcp_header_word_0 & ~NX_LOWER_16_MASK)) |
1573 ((ULONG) record_entry -> local_port);
1574 }
1575
1576 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
1577 if(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_TCP_TX_CHECKSUM)
1578 compute_checksum = 0;
1579 else
1580 compute_checksum = 1;
1581 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
1582 if(compute_checksum)
1583 {
1584
1585 /* Get the old checksum. */
1586 checksum = (USHORT)(tcp_header_ptr -> nx_tcp_header_word_4 >> NX_SHIFT_BY_16);
1587
1588 /* Check whether the port is updated. */
1589 if (record_entry -> external_port != record_entry -> local_port)
1590 {
1591
1592 /* Set the old port and new port. */
1593 old_port = record_entry -> external_port;
1594 new_port = record_entry -> local_port;
1595
1596 /* Adjust the checksum for port. */
1597 _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_port, sizeof(USHORT), (UCHAR *)&new_port, sizeof(USHORT));
1598 }
1599
1600 /* Set the old address and new address. */
1601 old_address = nat_ptr -> nx_nat_ip_ptr -> nx_ip_interface[nat_ptr -> nx_nat_global_interface_index].nx_interface_ip_address;
1602 new_address = record_entry -> local_ip_address;
1603
1604 /* Adjust the checksum for address. */
1605 _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_address, sizeof(LONG), (UCHAR *)&new_address, sizeof(LONG));
1606
1607 /* OK to clear the TCP checksum field to zero before the checksum update. */
1608 tcp_header_ptr -> nx_tcp_header_word_4 = tcp_header_ptr -> nx_tcp_header_word_4 & NX_LOWER_16_MASK;
1609
1610 /* Place the checksum into the first header word. */
1611 tcp_header_ptr -> nx_tcp_header_word_4 = tcp_header_ptr -> nx_tcp_header_word_4 | (ULONG)(checksum << NX_SHIFT_BY_16);
1612 }
1613 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
1614 else
1615 {
1616
1617 /* OK to clear the TCP checksum field to zero before the checksum update. */
1618 tcp_header_ptr -> nx_tcp_header_word_4 = tcp_header_ptr -> nx_tcp_header_word_4 & NX_LOWER_16_MASK;
1619
1620 /* Set the flag. */
1621 packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_TCP_TX_CHECKSUM;
1622 }
1623 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
1624 }
1625
1626 /* Swap endianness back before sending. */
1627 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_sequence_number);
1628 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_acknowledgment_number);
1629 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_0);
1630 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_3);
1631 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_4);
1632
1633 /* Check the entry found flag. */
1634 if (entry_found == NX_FALSE)
1635 {
1636
1637 /* Stop processing, recover packet length to Let NetXDuo process this packet. */
1638 packet_ptr -> nx_packet_prepend_ptr -= sizeof(NX_IPV4_HEADER);
1639 packet_ptr -> nx_packet_length += sizeof(NX_IPV4_HEADER);
1640
1641 /* Let NetXDuo process this pcaket. */
1642 return(NX_NAT_PACKET_CONSUMED_FAILED);
1643 }
1644
1645 /* Send the TCP packet onto the private host. */
1646 _nx_nat_ip_packet_send(nat_ptr, packet_ptr, record_entry, NX_NAT_INBOUND_PACKET, next_hop_address);
1647
1648 /* Return completion status. */
1649 return NX_SUCCESS;
1650 }
1651
1652
1653 /**************************************************************************/
1654 /* */
1655 /* FUNCTION RELEASE */
1656 /* */
1657 /* _nx_nat_process_inbound_UDP_packet PORTABLE C */
1658 /* 6.1 */
1659 /* AUTHOR */
1660 /* */
1661 /* Yuxin Zhou, Microsoft Corporation */
1662 /* */
1663 /* DESCRIPTION */
1664 /* */
1665 /* This function finds the local IP address:port for an incoming packet */
1666 /* in the NAT translation table and replaces the global packet */
1667 /* destination IP address and port with the local IP address andport. */
1668 /* If none is found, it rejects the packet. Otherwise it updates the UDP*/
1669 /* checksum with the changed IP address and port. The packet is then */
1670 /* sent to private host. */
1671 /* */
1672 /* INPUT */
1673 /* */
1674 /* nat_ptr Pointer to the NAT server */
1675 /* packet_ptr Pointer to the packet to process */
1676 /* entry_ptr Pointer to the entry */
1677 /* */
1678 /* OUTPUT */
1679 /* */
1680 /* status Actual completion status */
1681 /* NX_SUCCESS Successful completion status */
1682 /* NX_NAT_INVALID_IP_HEADER Invalid IP header */
1683 /* NX_NAT_BAD_UDP_CHECKSUM UDP checksum is invalid */
1684 /* */
1685 /* CALLS */
1686 /* */
1687 /* _nx_nat_inbound_entry_find Find inbound entry in entry list */
1688 /* _nx_nat_ip_packet_send Send packet to private interface */
1689 /* nx_packet_release Release the packet */
1690 /* */
1691 /* CALLED BY */
1692 /* */
1693 /* _nx_nat_process_inbound_packet Process inbound packets */
1694 /* */
1695 /* RELEASE HISTORY */
1696 /* */
1697 /* DATE NAME DESCRIPTION */
1698 /* */
1699 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1700 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1701 /* resulting in version 6.1 */
1702 /* */
1703 /**************************************************************************/
_nx_nat_process_inbound_UDP_packet(NX_NAT_DEVICE * nat_ptr,NX_PACKET * packet_ptr,NX_NAT_TRANSLATION_ENTRY * entry_ptr)1704 static UINT _nx_nat_process_inbound_UDP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr)
1705 {
1706
1707 UINT status;
1708 UINT entry_found;
1709 USHORT old_port;
1710 USHORT new_port;
1711 ULONG old_address;
1712 ULONG new_address;
1713 USHORT checksum;
1714 ULONG compute_checksum;
1715 ULONG next_hop_address;
1716 NX_UDP_HEADER *udp_header_ptr;
1717 NX_NAT_TRANSLATION_ENTRY *record_entry;
1718
1719
1720 /* Initialize local variables. */
1721 compute_checksum = 1;
1722 record_entry = NX_NULL;
1723 entry_found = NX_TRUE;
1724
1725 /* Pickup the pointer to the head of the UDP packet. */
1726 packet_ptr -> nx_packet_prepend_ptr += sizeof(NX_IPV4_HEADER);
1727 packet_ptr -> nx_packet_length -= sizeof(NX_IPV4_HEADER);
1728 udp_header_ptr = (NX_UDP_HEADER *) (packet_ptr -> nx_packet_prepend_ptr);
1729
1730 /* For little endian processors, adjust byte order for big endianness. */
1731 NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_0);
1732 NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1);
1733
1734 /* Find the inbound entry, set the packet private interface and next hop address. */
1735 status = _nx_nat_inbound_entry_find(nat_ptr, packet_ptr, entry_ptr, &record_entry, &next_hop_address);
1736
1737 /* Check for error. */
1738 if (status != NX_SUCCESS)
1739 {
1740
1741 #ifndef NX_DISABLE_NAT_INFO
1742 /* Update the count. */
1743 nat_ptr -> forwarded_packets_dropped++;
1744 #endif
1745
1746 /* Check the status. */
1747 if (status == NX_NAT_ENTRY_NOT_FOUND)
1748 {
1749
1750 /* Set the entry found flag. */
1751 entry_found = NX_FALSE;
1752 }
1753 else
1754 {
1755
1756 /* Release the packet */
1757 nx_packet_release(packet_ptr);
1758
1759 /* Return completion status. */
1760 return NX_SUCCESS;
1761 }
1762 }
1763 else
1764 {
1765
1766 /* Update the destination port if the NAT device mapped it to another port. */
1767 if (record_entry -> external_port != record_entry -> local_port)
1768 {
1769
1770 /* Translate the destination UDP port to the private host port. If translation
1771 does not involve port number this will essentially be the original port number. */
1772 udp_header_ptr -> nx_udp_header_word_0 = ((ULONG) (udp_header_ptr -> nx_udp_header_word_0 & ~NX_LOWER_16_MASK)) |
1773 ((ULONG) record_entry -> local_port);
1774 }
1775
1776 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
1777 if(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_UDP_TX_CHECKSUM)
1778 compute_checksum = 0;
1779 else
1780 compute_checksum = 1;
1781 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
1782
1783 /* Get the checksum. */
1784 checksum = udp_header_ptr -> nx_udp_header_word_1 & NX_LOWER_16_MASK;
1785
1786 /* UDP headers with 0 checksum should not be modified, RFC3022, Section4.1, Page8. */
1787 if (checksum == 0)
1788 compute_checksum = 0;
1789
1790 /* Check the checksum. */
1791 if(compute_checksum)
1792 {
1793
1794 /* Check whether the port is updated. */
1795 if (record_entry -> external_port != record_entry -> local_port)
1796 {
1797
1798 /* Set the old port and new port. */
1799 old_port = record_entry -> external_port;
1800 new_port = record_entry -> local_port;
1801
1802 /* Adjust the checksum for port. */
1803 _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_port, sizeof(USHORT), (UCHAR *)&new_port, sizeof(USHORT));
1804 }
1805
1806 /* Set the old address and new address. */
1807 old_address = nat_ptr -> nx_nat_ip_ptr -> nx_ip_interface[nat_ptr -> nx_nat_global_interface_index].nx_interface_ip_address;
1808 new_address = record_entry -> local_ip_address;
1809
1810 /* Adjust the checksum for address. */
1811 _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_address, sizeof(LONG), (UCHAR *)&new_address, sizeof(LONG));
1812
1813 /* OK to clear the UDP checksum field to zero before the checksum update. */
1814 udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 & ~NX_LOWER_16_MASK;
1815
1816 /* Place the checksum into the first header word. */
1817 udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 | checksum;
1818 }
1819 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
1820 else
1821 {
1822
1823 /* OK to clear the UDP checksum field to zero before the checksum update. */
1824 udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 & ~NX_LOWER_16_MASK;
1825
1826 /* Set the flag. */
1827 packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_UDP_TX_CHECKSUM;
1828 }
1829 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
1830 }
1831
1832 /* Swap UDP header byte order back to big endian before sending. For big endian processors,
1833 this will have no effect. */
1834 NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_0);
1835 NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1);
1836
1837 /* Check the packet consumed flag. */
1838 if (entry_found == NX_FALSE)
1839 {
1840
1841 /* Stop processing, recover packet length to Let NetXDuo process this packet. */
1842 packet_ptr -> nx_packet_prepend_ptr -= sizeof(NX_IPV4_HEADER);
1843 packet_ptr -> nx_packet_length += sizeof(NX_IPV4_HEADER);
1844
1845 /* Let NetXDuo process this pcaket. */
1846 return(NX_NAT_PACKET_CONSUMED_FAILED);
1847 }
1848
1849 /* Send the UDP packet onto the private host. */
1850 _nx_nat_ip_packet_send(nat_ptr, packet_ptr, record_entry, NX_NAT_INBOUND_PACKET, next_hop_address);
1851
1852 /* Return completion status. */
1853 return NX_SUCCESS;
1854 }
1855
1856
1857 /**************************************************************************/
1858 /* */
1859 /* FUNCTION RELEASE */
1860 /* */
1861 /* _nx_nat_process_inbound_ICMP_packet PORTABLE C */
1862 /* 6.1 */
1863 /* AUTHOR */
1864 /* */
1865 /* Yuxin Zhou, Microsoft Corporation */
1866 /* */
1867 /* DESCRIPTION */
1868 /* */
1869 /* This function finds the local IP address:port for an incoming packet */
1870 /* in the NAT translation table and replaces the global packet */
1871 /* IP address and queryID with the local IP address and queryID. */
1872 /* If none is found, rejects the packet. Otherwise it updates the ICMP */
1873 /* checksum with the changed IP address and port. The packet is then */
1874 /* sent to private host. */
1875 /* */
1876 /* INPUT */
1877 /* */
1878 /* nat_ptr Pointer to the NAT server */
1879 /* packet_ptr Pointer to the packet to process */
1880 /* entry_ptr Pointer to the entry */
1881 /* */
1882 /* OUTPUT */
1883 /* */
1884 /* status Actual completion status */
1885 /* NX_SUCCESS Successful completion status */
1886 /* (packet is not necessarily */
1887 /* forwarded) */
1888 /* */
1889 /* CALLS */
1890 /* */
1891 /* _nx_nat_inbound_entry_find Find inbound entry in entry list */
1892 /* _nx_nat_ip_packet_send Send packet to private interface */
1893 /* nx_packet_release Release the packet */
1894 /* */
1895 /* CALLED BY */
1896 /* */
1897 /* _nx_nat_process_inbound_packet Process inbound packets */
1898 /* */
1899 /* RELEASE HISTORY */
1900 /* */
1901 /* DATE NAME DESCRIPTION */
1902 /* */
1903 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1904 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1905 /* resulting in version 6.1 */
1906 /* */
1907 /**************************************************************************/
_nx_nat_process_inbound_ICMP_packet(NX_NAT_DEVICE * nat_ptr,NX_PACKET * packet_ptr,NX_NAT_TRANSLATION_ENTRY * entry_ptr)1908 static UINT _nx_nat_process_inbound_ICMP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr)
1909 {
1910 UINT status;
1911 UINT entry_found;
1912 ULONG sequence;
1913 UINT type;
1914 USHORT old_port;
1915 USHORT new_port;
1916 USHORT checksum;
1917 ULONG compute_checksum;
1918 ULONG next_hop_address;
1919 NX_ICMP_HEADER *icmp_header_ptr;
1920 NX_NAT_TRANSLATION_ENTRY *record_entry;
1921
1922
1923 /* Initialize local variables. */
1924 compute_checksum = 1;
1925 record_entry = NX_NULL;
1926 entry_found = NX_TRUE;
1927
1928 /* Get a pointer to the ICMP header. */
1929 packet_ptr -> nx_packet_prepend_ptr += sizeof(NX_IPV4_HEADER);
1930 packet_ptr -> nx_packet_length -= sizeof(NX_IPV4_HEADER);
1931 icmp_header_ptr = (NX_ICMP_HEADER *)(packet_ptr -> nx_packet_prepend_ptr);
1932
1933 /* Adjust ICMP header byte order for endianness. */
1934 NX_CHANGE_ULONG_ENDIAN(icmp_header_ptr -> nx_icmp_header_word_0);
1935 NX_CHANGE_ULONG_ENDIAN(icmp_header_ptr -> nx_icmp_header_word_1);
1936
1937 /* Extract the ICMP type and code. */
1938 type = icmp_header_ptr -> nx_icmp_header_word_0 >> 24;
1939
1940 /* Find the inbound entry, set the packet private interface and next hop address. */
1941 status = _nx_nat_inbound_entry_find(nat_ptr, packet_ptr, entry_ptr, &record_entry, &next_hop_address);
1942
1943 /* Check for error. */
1944 if (status != NX_SUCCESS)
1945 {
1946
1947 #ifndef NX_DISABLE_NAT_INFO
1948 /* Update the count. */
1949 nat_ptr -> forwarded_packets_dropped++;
1950 #endif
1951
1952 /* Check the status. */
1953 if (status == NX_NAT_ENTRY_NOT_FOUND)
1954 {
1955
1956 /* Set the entry found flag. */
1957 entry_found = NX_FALSE;
1958 }
1959 else
1960 {
1961
1962 /* Release the packet */
1963 nx_packet_release(packet_ptr);
1964
1965 /* Return completion status. */
1966 return NX_SUCCESS;
1967 }
1968 }
1969 else
1970 {
1971
1972 /* Check the type. */
1973 if ((type != NX_ICMP_ECHO_REPLY_TYPE) &&
1974 (type != NX_ICMP_ECHO_REQUEST_TYPE))
1975 {
1976
1977 #ifndef NX_DISABLE_NAT_INFO
1978 /* Unknown ICMP packet. Drop the packet and bail! */
1979 nat_ptr -> forwarded_packets_dropped++;
1980 #endif
1981
1982 nx_packet_release(packet_ptr);
1983
1984 return NX_SUCCESS;
1985 }
1986
1987 /* Now we have to translate the packet destination for private host address and
1988 update packet header checksum. */
1989 if ((type == NX_ICMP_ECHO_REPLY_TYPE) && (record_entry -> external_port != record_entry -> local_port))
1990 {
1991
1992 /* Restore the local host ICMP Query ID. */
1993 sequence = icmp_header_ptr -> nx_icmp_header_word_1 & NX_LOWER_16_MASK;
1994
1995 /* Restore the local host ICMP Query ID from the 'source port' field in the NAT table entry. */
1996 icmp_header_ptr -> nx_icmp_header_word_1 = (ULONG)(record_entry -> local_port << NX_SHIFT_BY_16) | sequence;
1997
1998 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
1999 if(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_ICMPV4_TX_CHECKSUM)
2000 compute_checksum = 0;
2001 else
2002 compute_checksum = 1;
2003 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
2004 if(compute_checksum)
2005 {
2006
2007 /* Set the old checksum. */
2008 checksum = icmp_header_ptr -> nx_icmp_header_word_0 & NX_LOWER_16_MASK;
2009
2010 /* Set the old port and new port. */
2011 old_port = entry_ptr -> external_port;
2012 new_port = record_entry -> local_port;
2013
2014 /* Adjust the checksum. */
2015 _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_port, sizeof(USHORT), (UCHAR *)&new_port, sizeof(USHORT));
2016
2017 /* Ok to zero out the checksum because we'll replace it with an updated checksum. */
2018 icmp_header_ptr -> nx_icmp_header_word_0 = icmp_header_ptr -> nx_icmp_header_word_0 & ~NX_LOWER_16_MASK;
2019
2020 /* Place the checksum into the first header word. */
2021 icmp_header_ptr -> nx_icmp_header_word_0 = icmp_header_ptr -> nx_icmp_header_word_0 | checksum;
2022 }
2023 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
2024 else
2025 {
2026
2027 /* Set the checksum to zero. */
2028 icmp_header_ptr -> nx_icmp_header_word_0 = icmp_header_ptr -> nx_icmp_header_word_0 & ~NX_LOWER_16_MASK;
2029
2030 /* Set the flag. */
2031 packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_ICMPV4_TX_CHECKSUM;
2032 }
2033 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
2034 }
2035 }
2036
2037 /* If NX_LITTLE_ENDIAN is defined, the headers need to be swapped to match
2038 that of the data area. */
2039 NX_CHANGE_ULONG_ENDIAN(icmp_header_ptr -> nx_icmp_header_word_0);
2040 NX_CHANGE_ULONG_ENDIAN(icmp_header_ptr -> nx_icmp_header_word_1);
2041
2042 /* Check the packet consumed flag. */
2043 if (entry_found == NX_FALSE)
2044 {
2045
2046 /* Stop processing, recover packet length to Let NetXDuo process this packet. */
2047 packet_ptr -> nx_packet_prepend_ptr -= sizeof(NX_IPV4_HEADER);
2048 packet_ptr -> nx_packet_length += sizeof(NX_IPV4_HEADER);
2049
2050 /* Let NetXDuo process this pcaket. */
2051 return(NX_NAT_PACKET_CONSUMED_FAILED);
2052 }
2053
2054 /* Send the ICMP packet onto the private host. */
2055 _nx_nat_ip_packet_send(nat_ptr, packet_ptr, record_entry, NX_NAT_INBOUND_PACKET, next_hop_address);
2056
2057 /* Return packet send completion status. */
2058 return NX_SUCCESS;
2059 }
2060
2061
2062 /**************************************************************************/
2063 /* */
2064 /* FUNCTION RELEASE */
2065 /* */
2066 /* _nx_nat_process_outbound_packet PORTABLE C */
2067 /* 6.1 */
2068 /* AUTHOR */
2069 /* */
2070 /* Yuxin Zhou, Microsoft Corporation */
2071 /* */
2072 /* DESCRIPTION */
2073 /* */
2074 /* This function processes a packet from a local host bound for the */
2075 /* external network. If a matching entry for the private host is not */
2076 /* found in the NAT translation table, one is created. Packets are then*/
2077 /* directed to protocol specific handlers for detailed processing of the*/
2078 /* packet before sending out on the external network. */
2079 /* */
2080 /* INPUT */
2081 /* */
2082 /* nat_ptr Pointer to the NAT server */
2083 /* packet_ptr Pointer to the packet to process */
2084 /* */
2085 /* OUTPUT */
2086 /* */
2087 /* status Actual completion status */
2088 /* NX_SUCCESS Successful completion status */
2089 /* NX_NAT_INVALID_PROTOCOL Unknown/unsupported protocol status*/
2090 /* */
2091 /* CALLS */
2092 /* */
2093 /* _nx_nat_process_outbound_TCP_packet */
2094 /* Handler for outbound TCP packets */
2095 /* _nx_nat_process_outbound_UDP_packet */
2096 /* Handler for outbound UDP packets */
2097 /* _nx_nat_process_outbound_ICMP_packet */
2098 /* Handler for outbound ICMP packets */
2099 /* nx_packet_release Release packet back to packet pool */
2100 /* */
2101 /* CALLED BY */
2102 /* */
2103 /* _nx_nat_packet_process Process packets forwarded to NAT by*/
2104 /* Netx */
2105 /* */
2106 /* RELEASE HISTORY */
2107 /* */
2108 /* DATE NAME DESCRIPTION */
2109 /* */
2110 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2111 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2112 /* resulting in version 6.1 */
2113 /* */
2114 /**************************************************************************/
_nx_nat_process_outbound_packet(NX_NAT_DEVICE * nat_ptr,NX_PACKET * packet_ptr)2115 static UINT _nx_nat_process_outbound_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr)
2116 {
2117
2118 UCHAR protocol;
2119 NX_IPV4_HEADER *ip_header_ptr;
2120 NX_NAT_TRANSLATION_ENTRY translation_entry;
2121
2122
2123 /* Set up an actual IP header pointer. */
2124 ip_header_ptr = (NX_IPV4_HEADER *) (packet_ptr -> nx_packet_prepend_ptr);
2125
2126 /* Determine what protocol the current IP datagram is. */
2127 protocol = (ip_header_ptr -> nx_ip_header_word_2 >> 16) & 0xFF;
2128
2129 /* Set up the search criteria in the NAT translation table. */
2130 memset(&translation_entry, 0, sizeof(NX_NAT_TRANSLATION_ENTRY));
2131 translation_entry.local_ip_address = ip_header_ptr -> nx_ip_header_source_ip;
2132 translation_entry.peer_ip_address = ip_header_ptr -> nx_ip_header_destination_ip;
2133 translation_entry.protocol = protocol;
2134
2135 /* Direct the packet to a protocol specific handler. */
2136 switch (protocol)
2137 {
2138
2139 case NX_PROTOCOL_TCP:
2140 /* Process the packet for TCP protocol. */
2141 _nx_nat_process_outbound_TCP_packet(nat_ptr, packet_ptr, &translation_entry);
2142 break;
2143
2144 case NX_PROTOCOL_UDP:
2145 /* Process the packet for UDP protocol. */
2146 _nx_nat_process_outbound_UDP_packet(nat_ptr, packet_ptr, &translation_entry);
2147 break;
2148
2149 case NX_PROTOCOL_ICMP:
2150 /* Process the packet for ICMP (including error message packets) protocol. */
2151 _nx_nat_process_outbound_ICMP_packet(nat_ptr, packet_ptr, &translation_entry);
2152 break;
2153
2154 default:
2155 {
2156
2157 #ifndef NX_DISABLE_NAT_INFO
2158 /* Update the count. */
2159 nat_ptr -> forwarded_packets_dropped++;
2160 #endif
2161
2162 /* Toss the IP packet since we don't know what to do with it! */
2163 nx_packet_release(packet_ptr);
2164
2165 return NX_NAT_INVALID_PROTOCOL;
2166 }
2167 }
2168
2169 /* Return completion status. */
2170 return NX_SUCCESS;
2171 }
2172
2173
2174 /**************************************************************************/
2175 /* */
2176 /* FUNCTION RELEASE */
2177 /* */
2178 /* _nx_nat_process_outbound_TCP_packet PORTABLE C */
2179 /* 6.1 */
2180 /* AUTHOR */
2181 /* */
2182 /* Yuxin Zhou, Microsoft Corporation */
2183 /* */
2184 /* DESCRIPTION */
2185 /* */
2186 /* This function processes a TCP packet from a local host on the private*/
2187 /* network destined for the external network with a global IP address */
2188 /* and port. The source IP address and port are replaced by NAT with a */
2189 /* global IP address:port. NAT then updates the TCP header checksum. */
2190 /* */
2191 /* INPUT */
2192 /* */
2193 /* nat_ptr Pointer to the NAT server */
2194 /* packet_ptr Pointer to the packet to process */
2195 /* entry_ptr Pointer to the entry */
2196 /* */
2197 /* OUTPUT */
2198 /* */
2199 /* status Actual completion status */
2200 /* NX_SUCCESS Successful completion status */
2201 /* */
2202 /* CALLS */
2203 /* */
2204 /* _nx_nat_outbound_entry_find Find outbound entry in entry list */
2205 /* _nx_nat_ip_packet_send Send packet to private interface */
2206 /* nx_packet_release Release the packet */
2207 /* */
2208 /* CALLED BY */
2209 /* */
2210 /* Application code */
2211 /* */
2212 /* RELEASE HISTORY */
2213 /* */
2214 /* DATE NAME DESCRIPTION */
2215 /* */
2216 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2217 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2218 /* resulting in version 6.1 */
2219 /* */
2220 /**************************************************************************/
_nx_nat_process_outbound_TCP_packet(NX_NAT_DEVICE * nat_ptr,NX_PACKET * packet_ptr,NX_NAT_TRANSLATION_ENTRY * entry_ptr)2221 static UINT _nx_nat_process_outbound_TCP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr)
2222 {
2223
2224 UINT status;
2225 USHORT old_port;
2226 USHORT new_port;
2227 ULONG old_address;
2228 ULONG new_address;
2229 USHORT checksum;
2230 ULONG compute_checksum;
2231 ULONG next_hop_address;
2232 NX_TCP_HEADER *tcp_header_ptr;
2233 NX_NAT_TRANSLATION_ENTRY *record_entry;
2234
2235
2236 /* Initialize local variables. */
2237 compute_checksum = 1;
2238
2239 /* Pickup the pointer to the head of the UDP packet. */
2240 packet_ptr -> nx_packet_prepend_ptr += sizeof(NX_IPV4_HEADER);
2241 packet_ptr -> nx_packet_length -= sizeof(NX_IPV4_HEADER);
2242 tcp_header_ptr = (NX_TCP_HEADER *) (packet_ptr -> nx_packet_prepend_ptr);
2243
2244 /* Adjust byte order for endianness. */
2245 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_0);
2246 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_sequence_number);
2247 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_acknowledgment_number);
2248 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_3);
2249 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_4);
2250
2251 /* Find the outbound entry, set the packet global interface and next hop address. */
2252 status = _nx_nat_outbound_entry_find(nat_ptr, packet_ptr, entry_ptr, &record_entry, &next_hop_address);
2253
2254 /* Check for error. */
2255 if (status != NX_SUCCESS)
2256 {
2257
2258 #ifndef NX_DISABLE_NAT_INFO
2259 /* Increase the session count of dropped forwarded packets. */
2260 nat_ptr -> forwarded_packets_dropped++;
2261 #endif
2262
2263 /* Release the packet back to the packet pool. */
2264 nx_packet_release(packet_ptr);
2265
2266 /* Return the error status. */
2267 return status;
2268 }
2269
2270 /* Update the source port if the NAT device mapped it to another port. */
2271 if (record_entry -> external_port != record_entry -> local_port)
2272 {
2273
2274 /* Yes, write to the upper bits of the TCP word. */
2275 tcp_header_ptr -> nx_tcp_header_word_0 = (tcp_header_ptr -> nx_tcp_header_word_0 & NX_LOWER_16_MASK) |
2276 (((ULONG) (record_entry -> external_port)) << NX_SHIFT_BY_16);
2277 }
2278
2279 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
2280 if(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_TCP_TX_CHECKSUM)
2281 compute_checksum = 0;
2282 else
2283 compute_checksum = 1;
2284 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
2285 if(compute_checksum)
2286 {
2287
2288 /* Get the old checksum. */
2289 checksum = (USHORT)(tcp_header_ptr -> nx_tcp_header_word_4 >> NX_SHIFT_BY_16);
2290
2291 /* Check whether the port is updated. */
2292 if (record_entry -> external_port != record_entry -> local_port)
2293 {
2294
2295 /* Set the old port and new port. */
2296 old_port = record_entry -> local_port;
2297 new_port = record_entry -> external_port;
2298
2299 /* Adjust the checksum for port. */
2300 _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_port, sizeof(USHORT), (UCHAR *)&new_port, sizeof(USHORT));
2301 }
2302
2303 /* Set the old address and new address. */
2304 old_address = record_entry -> local_ip_address;
2305 new_address = nat_ptr -> nx_nat_ip_ptr -> nx_ip_interface[nat_ptr -> nx_nat_global_interface_index].nx_interface_ip_address;
2306
2307 /* Adjust the checksum for address. */
2308 _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_address, sizeof(LONG), (UCHAR *)&new_address, sizeof(LONG));
2309
2310 /* OK to clear the TCP checksum field to zero before the checksum update. */
2311 tcp_header_ptr -> nx_tcp_header_word_4 = tcp_header_ptr -> nx_tcp_header_word_4 & NX_LOWER_16_MASK;
2312
2313 /* Place the checksum into the first header word. */
2314 tcp_header_ptr -> nx_tcp_header_word_4 = tcp_header_ptr -> nx_tcp_header_word_4 | (ULONG)(checksum << NX_SHIFT_BY_16);
2315 }
2316 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
2317 else
2318 {
2319
2320 /* OK to clear the TCP checksum field to zero before the checksum update. */
2321 tcp_header_ptr -> nx_tcp_header_word_4 = tcp_header_ptr -> nx_tcp_header_word_4 & NX_LOWER_16_MASK;
2322
2323 /* Set the flag. */
2324 packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_TCP_TX_CHECKSUM;
2325 }
2326 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
2327
2328 /* Swap byte order back to big endian before sending if little endian is specified. */
2329 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_0);
2330 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_sequence_number);
2331 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_acknowledgment_number);
2332 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_3);
2333 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_4);
2334
2335 /* Send the TCP packet onto the global host. */
2336 _nx_nat_ip_packet_send(nat_ptr,packet_ptr, record_entry, NX_NAT_OUTBOUND_PACKET, next_hop_address);
2337
2338 return NX_SUCCESS;
2339 }
2340
2341
2342 /**************************************************************************/
2343 /* */
2344 /* FUNCTION RELEASE */
2345 /* */
2346 /* _nx_nat_process_outbound_UDP_packet PORTABLE C */
2347 /* 6.1 */
2348 /* AUTHOR */
2349 /* */
2350 /* Yuxin Zhou, Microsoft Corporation */
2351 /* */
2352 /* DESCRIPTION */
2353 /* */
2354 /* This function processes a UDP packet from a local host destined for */
2355 /* the external network; NAT replaces the private IP address:port with a*/
2356 /* global IP address:port. NAT updates the UDP header checksum field for*/
2357 /* all packets having a non zero UDP packet checksum. */
2358 /* */
2359 /* INPUT */
2360 /* */
2361 /* nat_ptr Pointer to the NAT server */
2362 /* packet_ptr Pointer to the packet to process */
2363 /* entry_ptr Pointer to the entry */
2364 /* */
2365 /* OUTPUT */
2366 /* */
2367 /* status Actual completion status */
2368 /* NX_SUCCESS Successful completion status */
2369 /* NX_NAT_ZERO_UDP_CHECKSUM Illegal zero UDP header checksum */
2370 /* NX_NAT_BAD_UDP_CHECKSUM UDP header checksum is invalid */
2371 /* */
2372 /* CALLS */
2373 /* */
2374 /* _nx_nat_outbound_entry_find Find outbound entry in entry list */
2375 /* _nx_nat_ip_packet_send Send packet to private interface */
2376 /* nx_packet_release Release the packet */
2377 /* */
2378 /* CALLED BY */
2379 /* */
2380 /* Application code */
2381 /* */
2382 /* RELEASE HISTORY */
2383 /* */
2384 /* DATE NAME DESCRIPTION */
2385 /* */
2386 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2387 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2388 /* resulting in version 6.1 */
2389 /* */
2390 /**************************************************************************/
_nx_nat_process_outbound_UDP_packet(NX_NAT_DEVICE * nat_ptr,NX_PACKET * packet_ptr,NX_NAT_TRANSLATION_ENTRY * entry_ptr)2391 static UINT _nx_nat_process_outbound_UDP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr)
2392 {
2393
2394 UINT status;
2395 USHORT old_port;
2396 USHORT new_port;
2397 ULONG old_address;
2398 ULONG new_address;
2399 USHORT checksum;
2400 ULONG compute_checksum;
2401 ULONG next_hop_address;
2402 NX_UDP_HEADER *udp_header_ptr;
2403 NX_NAT_TRANSLATION_ENTRY *record_entry;
2404
2405 /* Initialize local variables. */
2406 compute_checksum = 1;
2407
2408 /* Pickup the pointer to the head of the UDP packet. */
2409 packet_ptr -> nx_packet_prepend_ptr += sizeof(NX_IPV4_HEADER);
2410 packet_ptr -> nx_packet_length -= sizeof(NX_IPV4_HEADER);
2411 udp_header_ptr = (NX_UDP_HEADER *) (packet_ptr -> nx_packet_prepend_ptr);
2412
2413 /* For little endian processors, swap byte order to little endian. */
2414 NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_0);
2415 NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1);
2416
2417 /* Find the outbound entry, set the packet global interface and next hop address. */
2418 status = _nx_nat_outbound_entry_find(nat_ptr, packet_ptr, entry_ptr, &record_entry, &next_hop_address);
2419
2420 /* Check for error. */
2421 if (status != NX_SUCCESS)
2422 {
2423
2424 #ifndef NX_DISABLE_NAT_INFO
2425 /* Increase the session count of dropped forwarded packets. */
2426 nat_ptr -> forwarded_packets_dropped++;
2427 #endif
2428
2429 /* Release the packet back to the packet pool. */
2430 nx_packet_release(packet_ptr);
2431
2432 /* Return the error status. */
2433 return status;
2434 }
2435
2436 /* OK to zero out the checksum field so we can update the header with a new checksum later. */
2437 udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 & ~NX_LOWER_16_MASK;
2438
2439 /* Did NAT assign a global UDP source port? */
2440 if (record_entry -> external_port != record_entry -> local_port)
2441 {
2442
2443 /* Yes, so replace local host UDP port with NAT global inside UDP port in the header. */
2444 udp_header_ptr -> nx_udp_header_word_0 = (udp_header_ptr -> nx_udp_header_word_0 & NX_LOWER_16_MASK) |
2445 (((ULONG) (record_entry -> external_port)) << NX_SHIFT_BY_16);
2446 }
2447
2448 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
2449 if(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_UDP_TX_CHECKSUM)
2450 compute_checksum = 0;
2451 else
2452 compute_checksum = 1;
2453 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
2454
2455 /* Get the old checksum. */
2456 checksum = udp_header_ptr -> nx_udp_header_word_1 & NX_LOWER_16_MASK;
2457
2458 /* UDP headers with 0 checksum should not be modified, RFC3022, Section4.1, Page8. */
2459 if (checksum == 0)
2460 compute_checksum = 0;
2461
2462 /* Compute the checksum. */
2463 if(compute_checksum)
2464 {
2465
2466 /* Check whether the port is updated. */
2467 if (record_entry -> external_port != record_entry -> local_port)
2468 {
2469
2470 /* Set the old port and new port. */
2471 old_port = record_entry -> local_port;
2472 new_port = record_entry -> external_port;
2473
2474 /* Adjust the checksum for port. */
2475 _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_port, sizeof(USHORT), (UCHAR *)&new_port, sizeof(USHORT));
2476 }
2477
2478 /* Set the old address and new address. */
2479 old_address = record_entry -> local_ip_address;
2480 new_address = nat_ptr -> nx_nat_ip_ptr -> nx_ip_interface[nat_ptr -> nx_nat_global_interface_index].nx_interface_ip_address;
2481
2482 /* Adjust the checksum for address. */
2483 _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_address, sizeof(LONG), (UCHAR *)&new_address, sizeof(LONG));
2484
2485 /* OK to clear the UDP checksum field to zero before the checksum update. */
2486 udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 & ~NX_LOWER_16_MASK;
2487
2488 /* Place the checksum into the first header word. */
2489 udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 | checksum;
2490 }
2491 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
2492 else
2493 {
2494
2495 /* OK to clear the UDP checksum field to zero before the checksum update. */
2496 udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 & ~NX_LOWER_16_MASK;
2497
2498 /* Set the flag. */
2499 packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_UDP_TX_CHECKSUM;
2500 }
2501 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
2502
2503 /* If NX_LITTLE_ENDIAN is defined, the headers need to be swapped to match
2504 that of the data area. */
2505 NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_0);
2506 NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1);
2507
2508 /* Send the UDP packet onto the global host. */
2509 _nx_nat_ip_packet_send(nat_ptr, packet_ptr, record_entry, NX_NAT_OUTBOUND_PACKET, next_hop_address);
2510
2511 /* Return packet send completion status. */
2512 return NX_SUCCESS;
2513 }
2514
2515
2516 /**************************************************************************/
2517 /* */
2518 /* FUNCTION RELEASE */
2519 /* */
2520 /* _nx_nat_process_outbound_ICMP_packet PORTABLE C */
2521 /* 6.1 */
2522 /* AUTHOR */
2523 /* */
2524 /* Yuxin Zhou, Microsoft Corporation */
2525 /* */
2526 /* DESCRIPTION */
2527 /* */
2528 /* This function processes a ICMP packet from a local network host for */
2529 /* sending out onto the external network. NAT replaces the private */
2530 /* source IP address and local query ID with a global source IP address */
2531 /* and query ID. NAT then recomputes the ICMP header checksum. */
2532 /* */
2533 /* INPUT */
2534 /* */
2535 /* nat_ptr Pointer to the NAT server */
2536 /* packet_ptr Pointer to the packet to process */
2537 /* entry_ptr Pointer to the entry */
2538 /* */
2539 /* OUTPUT */
2540 /* */
2541 /* status Actual completion status */
2542 /* NX_SUCCESS Successful completion status */
2543 /* NX_NAT_BAD_ICMP_CHECKSUM Packet failed ICMP checksum check */
2544 /* NX_NAT_INVALID_IP_HEADER Packet has an invalid IP header */
2545 /* */
2546 /* CALLS */
2547 /* */
2548 /* _nx_nat_outbound_entry_find Find outbound entry in entry list */
2549 /* _nx_nat_ip_packet_send Send packet to private interface */
2550 /* nx_packet_release Release the packet */
2551 /* */
2552 /* CALLED BY */
2553 /* */
2554 /* Application code */
2555 /* */
2556 /* RELEASE HISTORY */
2557 /* */
2558 /* DATE NAME DESCRIPTION */
2559 /* */
2560 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2561 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2562 /* resulting in version 6.1 */
2563 /* */
2564 /**************************************************************************/
_nx_nat_process_outbound_ICMP_packet(NX_NAT_DEVICE * nat_ptr,NX_PACKET * packet_ptr,NX_NAT_TRANSLATION_ENTRY * entry_ptr)2565 static UINT _nx_nat_process_outbound_ICMP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr)
2566 {
2567
2568 UINT status;
2569 ULONG sequence;
2570 UINT is_icmp_error_msg;
2571 NX_ICMP_HEADER *icmp_header_ptr;
2572 UINT type;
2573 USHORT old_port;
2574 USHORT new_port;
2575 USHORT checksum;
2576 ULONG compute_checksum;
2577 ULONG next_hop_address;
2578 NX_NAT_TRANSLATION_ENTRY *record_entry;
2579
2580
2581 /* Initialize local variables. */
2582 compute_checksum = 1;
2583
2584 /* Pickup the pointer to the head of the ICMP packet. */
2585 packet_ptr -> nx_packet_prepend_ptr += sizeof(NX_IPV4_HEADER);
2586 packet_ptr -> nx_packet_length -= sizeof(NX_IPV4_HEADER);
2587 icmp_header_ptr = (NX_ICMP_HEADER *)(packet_ptr -> nx_packet_prepend_ptr);
2588
2589 /* Swap ENDian-ness for our ICMP header. We've only swapped the IP header data so far. */
2590 NX_CHANGE_ULONG_ENDIAN(icmp_header_ptr -> nx_icmp_header_word_0);
2591 NX_CHANGE_ULONG_ENDIAN(icmp_header_ptr -> nx_icmp_header_word_1);
2592
2593 /* Extract the ICMP type and code. */
2594 type = icmp_header_ptr -> nx_icmp_header_word_0 >> 24;
2595
2596 /* Determine if this outbound packet an ICMP error message packet. */
2597 _nx_nat_packet_is_icmp_error_message(packet_ptr, &is_icmp_error_msg);
2598
2599 /* Is the this an error message packet? */
2600 if (is_icmp_error_msg)
2601 {
2602
2603 #ifndef NX_DISABLE_NAT_INFO
2604 /* Drop the packet and bail! */
2605 nat_ptr -> forwarded_packets_dropped++;
2606 #endif
2607
2608 /* Release the packet. */
2609 nx_packet_release(packet_ptr);
2610
2611 /* Return completion status. */
2612 return NX_SUCCESS;
2613 }
2614
2615 /* Find the outbound entry, set the packet global interface and next hop address. */
2616 status = _nx_nat_outbound_entry_find(nat_ptr, packet_ptr, entry_ptr, &record_entry, &next_hop_address);
2617
2618 /* Check for error. */
2619 if (status != NX_SUCCESS)
2620 {
2621
2622 #ifndef NX_DISABLE_NAT_INFO
2623 /* Increase the session count of dropped forwarded packets. */
2624 nat_ptr -> forwarded_packets_dropped++;
2625 #endif
2626
2627 /* Release the packet back to the packet pool. */
2628 nx_packet_release(packet_ptr);
2629
2630 /* Return the error status. */
2631 return status;
2632 }
2633
2634 /* Update the ICMP Query ID ("port") if the NAT device mapped it to another Query ID
2635 but not if this is a local host responding to a REQUEST ICMP packet, in which case
2636 it must keep the same Query ID. */
2637 if ((type != NX_ICMP_ECHO_REPLY_TYPE) && (record_entry -> external_port != record_entry -> local_port))
2638 {
2639
2640 /* Pick up the ICMP sequence number. */
2641 sequence = icmp_header_ptr -> nx_icmp_header_word_1 & NX_LOWER_16_MASK;
2642
2643 /* Set the ICMP Query ID in the ICMP header. */
2644 icmp_header_ptr -> nx_icmp_header_word_1 = (ULONG) (record_entry -> external_port << NX_SHIFT_BY_16) | sequence;
2645
2646 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
2647 if(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_ICMPV4_TX_CHECKSUM)
2648 compute_checksum = 0;
2649 else
2650 compute_checksum = 1;
2651 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
2652 if(compute_checksum)
2653 {
2654
2655 /* Set the old checksum. */
2656 checksum = icmp_header_ptr -> nx_icmp_header_word_0 & NX_LOWER_16_MASK;
2657
2658 /* Set the old port and new port. */
2659 old_port = record_entry -> local_port;
2660 new_port = record_entry -> external_port;
2661
2662 /* Adjust the checksum. */
2663 _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_port, sizeof(USHORT), (UCHAR *)&new_port, sizeof(USHORT));
2664
2665 /* Ok to zero out the checksum because we'll replace it with an updated checksum. */
2666 icmp_header_ptr -> nx_icmp_header_word_0 = icmp_header_ptr -> nx_icmp_header_word_0 & ~NX_LOWER_16_MASK;
2667
2668 /* Place the checksum into the first header word. */
2669 icmp_header_ptr -> nx_icmp_header_word_0 = icmp_header_ptr -> nx_icmp_header_word_0 | checksum;
2670 }
2671 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
2672 else
2673 {
2674
2675 /* Set the checksum to zero. */
2676 icmp_header_ptr -> nx_icmp_header_word_0 = icmp_header_ptr -> nx_icmp_header_word_0 & ~NX_LOWER_16_MASK;
2677
2678 /* Set the flag. */
2679 packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_ICMPV4_TX_CHECKSUM;
2680 }
2681 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
2682 }
2683
2684 /* If NX_LITTLE_ENDIAN is defined, the headers need to be swapped to match
2685 that of the data area. */
2686 NX_CHANGE_ULONG_ENDIAN(icmp_header_ptr -> nx_icmp_header_word_0);
2687 NX_CHANGE_ULONG_ENDIAN(icmp_header_ptr -> nx_icmp_header_word_1);
2688
2689 /* Send the ICMP packet onto the global host. */
2690 _nx_nat_ip_packet_send(nat_ptr, packet_ptr, record_entry, NX_NAT_OUTBOUND_PACKET, next_hop_address);
2691
2692 /* Return completion status. */
2693 return NX_SUCCESS;
2694 }
2695
2696
2697 /**************************************************************************/
2698 /* */
2699 /* FUNCTION RELEASE */
2700 /* */
2701 /* _nx_nat_ip_packet_send PORTABLE C */
2702 /* 6.1 */
2703 /* AUTHOR */
2704 /* */
2705 /* Yuxin Zhou, Microsoft Corporation */
2706 /* */
2707 /* DESCRIPTION */
2708 /* */
2709 /* This function is the NAT equivalent of nx_ip_packet_send. It handles */
2710 /* all packets inbound or outbound of any protocol and forwards them */
2711 /* directly to the driver. */
2712 /* */
2713 /* This function also handles fragmented datagrams. */
2714 /* */
2715 /* INPUT */
2716 /* */
2717 /* nat_ptr Pointer to NAT server */
2718 /* packet_ptr Pointer to packet */
2719 /* entry_ptr Pointer to NAT entry */
2720 /* packet_type Packet type(inbound/outbound) */
2721 /* next_hop_address Next hop address to target */
2722 /* */
2723 /* OUTPUT */
2724 /* */
2725 /* status Actual completion status. */
2726 /* NX_SUCCESS Successful completion status */
2727 /* NX_NAT_FRAGMENT_QUEUE_NOT_FOUND Fragment queue for datagram */
2728 /* not found */
2729 /* CALLS */
2730 /* */
2731 /* nx_packet_release Release the packet */
2732 /* _nx_packet_data_append Append the overflow data */
2733 /* _nx_nat_checksum_adjust Adjust checksum for NAT changes */
2734 /* to IP header */
2735 /* _nx_ip_driver_packet_send Forward packet to driver to send*/
2736 /* */
2737 /* CALLED BY */
2738 /* */
2739 /* _nx_nat_process_outbound_TCP_packet Process outbound TCP packet */
2740 /* _nx_nat_process_outbound_UDP_packet Process outbound UDP packet */
2741 /* _nx_nat_process_outbound_ICMP_packet Process outbound ICMP packet */
2742 /* _nx_nat_process_inbound_TCP_packet Process outbound TCP packet */
2743 /* _nx_nat_process_inbound_UDP_packet Process outbound UDP packet */
2744 /* _nx_nat_process_inbound_ICMP_packet Process outbound ICMP packet */
2745 /* */
2746 /* RELEASE HISTORY */
2747 /* */
2748 /* DATE NAME DESCRIPTION */
2749 /* */
2750 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2751 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2752 /* resulting in version 6.1 */
2753 /* */
2754 /**************************************************************************/
_nx_nat_ip_packet_send(NX_NAT_DEVICE * nat_ptr,NX_PACKET * packet_ptr,NX_NAT_TRANSLATION_ENTRY * entry_ptr,UCHAR packet_type,ULONG next_hop_address)2755 static VOID _nx_nat_ip_packet_send(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr, UCHAR packet_type, ULONG next_hop_address)
2756 {
2757
2758 ULONG fragment_bits;
2759 ULONG old_address;
2760 ULONG new_address;
2761 ULONG old_fragment;
2762 ULONG new_fragment;
2763 USHORT checksum;
2764 ULONG compute_checksum = 1;
2765 ULONG destination_ip;
2766 UINT status;
2767 NX_IPV4_HEADER *ip_header_ptr;
2768
2769
2770 /* Pickup the pointer to the head of the ICMP packet. */
2771 packet_ptr -> nx_packet_prepend_ptr -= sizeof(NX_IPV4_HEADER);
2772 packet_ptr -> nx_packet_length += sizeof(NX_IPV4_HEADER);
2773 ip_header_ptr = (NX_IPV4_HEADER *) (packet_ptr -> nx_packet_prepend_ptr);
2774
2775 /* Check the packet type. */
2776 if (packet_type == NX_NAT_OUTBOUND_PACKET)
2777 {
2778
2779 /* Update the source ip address. */
2780 ip_header_ptr -> nx_ip_header_source_ip = nat_ptr -> nx_nat_ip_ptr -> nx_ip_interface[nat_ptr -> nx_nat_global_interface_index].nx_interface_ip_address;
2781
2782 /* Set the local address and external address. */
2783 old_address = entry_ptr -> local_ip_address;
2784 new_address = nat_ptr -> nx_nat_ip_ptr -> nx_ip_interface[nat_ptr -> nx_nat_global_interface_index].nx_interface_ip_address;
2785 }
2786 else
2787 {
2788 /* Update the destination ip address. */
2789 ip_header_ptr -> nx_ip_header_destination_ip = entry_ptr -> local_ip_address;
2790
2791 /* Set the old address and new address. */
2792 old_address = nat_ptr -> nx_nat_ip_ptr -> nx_ip_interface[nat_ptr -> nx_nat_global_interface_index].nx_interface_ip_address;
2793 new_address = entry_ptr -> local_ip_address;
2794 }
2795
2796 /* Record the destination IP address. */
2797 destination_ip = ip_header_ptr -> nx_ip_header_destination_ip;
2798
2799 /* Record the fragment bit. */
2800 fragment_bits = (ip_header_ptr -> nx_ip_header_word_1 & NX_IP_DONT_FRAGMENT);
2801 old_fragment = ip_header_ptr -> nx_ip_header_word_1 & NX_LOWER_16_MASK;
2802 new_fragment = old_fragment;
2803
2804 /* Check if the packet is fragmented and if the fragment field is not zero. */
2805 if ((fragment_bits != NX_IP_DONT_FRAGMENT) && (old_fragment != 0))
2806 {
2807
2808 /* Clear the fragment field. */
2809 ip_header_ptr -> nx_ip_header_word_1 = ip_header_ptr -> nx_ip_header_word_1 & ~NX_LOWER_16_MASK;
2810 new_fragment = 0;
2811 }
2812
2813 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
2814 if(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_IPV4_TX_CHECKSUM)
2815 compute_checksum = 0;
2816 else
2817 compute_checksum = 1;
2818 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
2819
2820 /* Compute the checksum. */
2821 if(compute_checksum)
2822 {
2823
2824 /* Get the checksum. */
2825 checksum = ip_header_ptr -> nx_ip_header_word_2 & NX_LOWER_16_MASK;
2826
2827 /* Adjust the checksum for address. */
2828 _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_address, sizeof(LONG), (UCHAR *)&new_address, sizeof(LONG));
2829
2830 /* Check if the fragment field is updated. */
2831 if (old_fragment != new_fragment)
2832 {
2833
2834 /* Adjust the checksum for fragment field. */
2835 _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_fragment, sizeof(LONG), (UCHAR *)&new_fragment, sizeof(LONG));
2836 }
2837
2838 /* Clear the checksum value. */
2839 ip_header_ptr -> nx_ip_header_word_2 = ip_header_ptr -> nx_ip_header_word_2 & ~NX_LOWER_16_MASK;
2840
2841 /* Place the checksum into the header word. */
2842 ip_header_ptr -> nx_ip_header_word_2 = ip_header_ptr -> nx_ip_header_word_2 | checksum;
2843 }
2844 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
2845 else
2846 {
2847
2848 /* Clear the checksum value. */
2849 ip_header_ptr -> nx_ip_header_word_2 = ip_header_ptr -> nx_ip_header_word_2 & ~NX_LOWER_16_MASK;
2850
2851 /* Set the flag. */
2852 packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_IPV4_TX_CHECKSUM;
2853 }
2854 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
2855
2856 /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will
2857 swap the endian of the IP header. */
2858 NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_0);
2859 NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_1);
2860 NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_2);
2861 NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_source_ip);
2862 NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_destination_ip);
2863
2864 /* Check if the packet can fill physical header. */
2865 status = _nx_packet_data_adjust(packet_ptr, NX_PHYSICAL_HEADER);
2866
2867 /* Check status. */
2868 if (status)
2869 {
2870
2871 #ifndef NX_DISABLE_NAT_INFO
2872 /* Update the count. */
2873 nat_ptr -> forwarded_packets_dropped ++;
2874 #endif
2875
2876 /* Release the packet. */
2877 _nx_packet_release(packet_ptr);
2878 return;
2879 }
2880
2881 #ifndef NX_DISABLE_NAT_INFO
2882 /* Update the packet sent count. */
2883 nat_ptr -> forwarded_packets_sent++;
2884 #endif
2885
2886 /* Call the function to directly forward the packet. */
2887 _nx_ip_driver_packet_send(nat_ptr -> nx_nat_ip_ptr, packet_ptr, destination_ip, fragment_bits, next_hop_address);
2888 return;
2889 }
2890
2891
2892 /**************************************************************************/
2893 /* */
2894 /* FUNCTION RELEASE */
2895 /* */
2896 /* _nx_nat_inbound_entry_find PORTABLE C */
2897 /* 6.1 */
2898 /* AUTHOR */
2899 /* */
2900 /* Yuxin Zhou, Microsoft Corporation */
2901 /* */
2902 /* DESCRIPTION */
2903 /* */
2904 /* This function finds the inbound entry in NAT translation entry list, */
2905 /* */
2906 /* INPUT */
2907 /* */
2908 /* nat_ptr Pointer to NAT server */
2909 /* packet_ptr Pointer to packet */
2910 /* entry_ptr Pointer to NAT entry */
2911 /* entry_ptr Pointer to the matched entry */
2912 /* next_hop_address The next hop address for route */
2913 /* */
2914 /* OUTPUT */
2915 /* */
2916 /* NX_SUCCESS Successful completion status */
2917 /* */
2918 /* CALLS */
2919 /* */
2920 /* _nx_nat_utility_get_source_port Extract source port from packet */
2921 /* _nx_nat_utility_get_destination_port */
2922 /* Extract destination port from */
2923 /* packet */
2924 /* _nx_nat_entry_create Create entry for packet in NAT */
2925 /* translation table */
2926 /* _nx_nat_entry_find Find the entry */
2927 /* _nx_ip_route_find Find the suitable interface */
2928 /* */
2929 /* CALLED BY */
2930 /* */
2931 /* _nx_nat_process_inbound_TCP_packet Process outbound TCP packet */
2932 /* _nx_nat_process_inbound_UDP_packet Process outbound UDP packet */
2933 /* _nx_nat_process_inbound_ICMP_packet Process outbound ICMP packet */
2934 /* */
2935 /* RELEASE HISTORY */
2936 /* */
2937 /* DATE NAME DESCRIPTION */
2938 /* */
2939 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2940 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2941 /* resulting in version 6.1 */
2942 /* */
2943 /**************************************************************************/
_nx_nat_inbound_entry_find(NX_NAT_DEVICE * nat_ptr,NX_PACKET * packet_ptr,NX_NAT_TRANSLATION_ENTRY * entry_ptr,NX_NAT_TRANSLATION_ENTRY ** matched_entry_ptr,ULONG * next_hop_address)2944 static UINT _nx_nat_inbound_entry_find(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr,
2945 NX_NAT_TRANSLATION_ENTRY **matched_entry_ptr, ULONG *next_hop_address)
2946 {
2947
2948 UINT status;
2949 ULONG timeout;
2950 NX_NAT_TRANSLATION_ENTRY *record_entry;
2951
2952
2953 /* Check the protocol. */
2954 if ((entry_ptr -> protocol == NX_PROTOCOL_TCP) || (entry_ptr -> protocol == NX_PROTOCOL_UDP))
2955 {
2956
2957 /* Get sender's source port. */
2958 _nx_nat_utility_get_source_port(packet_ptr, entry_ptr -> protocol, &entry_ptr -> peer_port);
2959 }
2960
2961 /* Get the destination port from header data. */
2962 _nx_nat_utility_get_destination_port(packet_ptr, entry_ptr -> protocol, &entry_ptr -> external_port);
2963
2964 /* Check the timeout for all dynamic entries. */
2965 _nx_nat_entry_timeout_check(nat_ptr);
2966
2967 /* Now search the table for a matching NAT translation entry. */
2968 _nx_nat_entry_find(nat_ptr, entry_ptr, &record_entry, NX_NAT_INBOUND_PACKET, NX_TRUE);
2969
2970 /* Was a matching entry found in our translation table? */
2971 if (!record_entry)
2972 {
2973
2974 /* Next see if the destination is a local host server. */
2975
2976 /* Find a 'server' for packet destination IP address and port */
2977 _nx_nat_entry_find(nat_ptr, entry_ptr, &record_entry, NX_NAT_INBOUND_PACKET, NX_FALSE);
2978
2979 /* Check the record entry. */
2980 if (record_entry)
2981 {
2982
2983 /* We found a matching server entry in the table. Now create an
2984 entry specifically for this packet. */
2985
2986 /* Get the private IP address from the entry we just found, and apply to the new entry we're creating. */
2987 entry_ptr -> local_ip_address = record_entry -> local_ip_address;
2988
2989 /* Check the private inside port. */
2990 if (record_entry -> local_port == 0)
2991 {
2992
2993 /* Set the private inside port same as global inside port. */
2994 entry_ptr -> local_port = entry_ptr -> external_port;
2995 }
2996 else
2997 {
2998
2999 /* Set private inside port. */
3000 entry_ptr -> local_port = record_entry -> local_port;
3001 }
3002
3003 /* Set the entry expiration timeout. */
3004 if (entry_ptr -> protocol == NX_PROTOCOL_TCP)
3005 {
3006
3007 /* TCP session. */
3008 timeout = NX_NAT_TCP_SESSION_TIMEOUT;
3009 }
3010 else
3011 {
3012
3013 /* Non-TCP session. */
3014 timeout = NX_NAT_NON_TCP_SESSION_TIMEOUT;
3015 }
3016
3017 /* Now create the entry. */
3018 status = _nx_nat_entry_create(nat_ptr, entry_ptr -> protocol,
3019 entry_ptr -> local_ip_address,
3020 entry_ptr -> peer_ip_address,
3021 entry_ptr -> local_port,
3022 entry_ptr -> external_port,
3023 entry_ptr -> peer_port,
3024 timeout,
3025 &record_entry);
3026
3027 /* Check for error. */
3028 if (status != NX_SUCCESS)
3029 {
3030
3031 /* Return status.*/
3032 return status;
3033 }
3034 }
3035 else
3036 {
3037
3038 /* Return status.*/
3039 return (NX_NAT_ENTRY_NOT_FOUND);
3040 }
3041 }
3042
3043 /* Clear the packet interface as private interface. */
3044 packet_ptr -> nx_packet_address.nx_packet_interface_ptr = NX_NULL;
3045
3046 /* Set the inbound interface and next hop address. */
3047 if(_nx_ip_route_find(nat_ptr -> nx_nat_ip_ptr, record_entry -> local_ip_address,
3048 &packet_ptr -> nx_packet_address.nx_packet_interface_ptr, next_hop_address) != NX_SUCCESS)
3049 {
3050
3051 /* No suitable private interface configured. */
3052
3053 /* Return the error status. */
3054 return (NX_NAT_ROUTE_FIND_ERROR);
3055 }
3056
3057 /* Set the matched entry pointer. */
3058 *matched_entry_ptr = record_entry;
3059
3060 /* Return success. */
3061 return (NX_SUCCESS);
3062 }
3063
3064
3065 /**************************************************************************/
3066 /* */
3067 /* FUNCTION RELEASE */
3068 /* */
3069 /* _nx_nat_outbound_entry_find PORTABLE C */
3070 /* 6.1 */
3071 /* AUTHOR */
3072 /* */
3073 /* Yuxin Zhou, Microsoft Corporation */
3074 /* */
3075 /* DESCRIPTION */
3076 /* */
3077 /* This function finds the outbound entry in NAT translation entry list.*/
3078 /* */
3079 /* INPUT */
3080 /* */
3081 /* nat_ptr Pointer to NAT server */
3082 /* packet_ptr Pointer to packet */
3083 /* entry_ptr Pointer to NAT entry */
3084 /* entry_ptr Pointer to the matched entry */
3085 /* next_hop_address The next hop address for route */
3086 /* */
3087 /* OUTPUT */
3088 /* */
3089 /* NX_SUCCESS Successful completion status */
3090 /* */
3091 /* CALLS */
3092 /* */
3093 /* _nx_nat_utility_get_source_port Extract source port from packet */
3094 /* _nx_nat_utility_get_destination_port */
3095 /* Extract destination port from */
3096 /* packet */
3097 /* _nx_nat_entry_create Create entry for packet in NAT */
3098 /* translation table */
3099 /* _nx_nat_entry_find Find the entry */
3100 /* _nx_ip_route_find Find the suitable interface */
3101 /* */
3102 /* CALLED BY */
3103 /* */
3104 /* _nx_nat_process_outbound_TCP_packet Process outbound TCP packet */
3105 /* _nx_nat_process_outbound_UDP_packet Process outbound UDP packet */
3106 /* _nx_nat_process_outbound_ICMP_packet Process outbound ICMP packet */
3107 /* */
3108 /* RELEASE HISTORY */
3109 /* */
3110 /* DATE NAME DESCRIPTION */
3111 /* */
3112 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3113 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3114 /* resulting in version 6.1 */
3115 /* */
3116 /**************************************************************************/
_nx_nat_outbound_entry_find(NX_NAT_DEVICE * nat_ptr,NX_PACKET * packet_ptr,NX_NAT_TRANSLATION_ENTRY * entry_ptr,NX_NAT_TRANSLATION_ENTRY ** matched_entry_ptr,ULONG * next_hop_address)3117 static UINT _nx_nat_outbound_entry_find(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr,
3118 NX_NAT_TRANSLATION_ENTRY **matched_entry_ptr, ULONG *next_hop_address)
3119 {
3120
3121 UINT status;
3122 ULONG timeout;
3123 NX_NAT_TRANSLATION_ENTRY *record_entry;
3124
3125
3126 /* Get source ports from the header. */
3127 _nx_nat_utility_get_source_port(packet_ptr, entry_ptr -> protocol, &(entry_ptr -> local_port));
3128
3129 /* Check the protocol. */
3130 if ((entry_ptr -> protocol == NX_PROTOCOL_TCP) || (entry_ptr -> protocol == NX_PROTOCOL_UDP))
3131 {
3132
3133 /* Get destination port from the header. */
3134 _nx_nat_utility_get_destination_port(packet_ptr, entry_ptr -> protocol, &(entry_ptr -> peer_port));
3135 }
3136
3137 /* Check the timeout for all dynamic entries. */
3138 _nx_nat_entry_timeout_check(nat_ptr);
3139
3140 /* Search the table for a match. */
3141 _nx_nat_entry_find(nat_ptr, entry_ptr, &record_entry, NX_NAT_OUTBOUND_PACKET, NX_TRUE);
3142
3143 /* Was a matching table entry found? */
3144 if (!record_entry)
3145 {
3146
3147 /* Find the available port. */
3148 status = _nx_nat_find_available_port(nat_ptr, entry_ptr -> protocol, &entry_ptr -> external_port);
3149
3150 /* Check for error. */
3151 if (status != NX_SUCCESS)
3152 {
3153
3154 return status;
3155 }
3156
3157 /* Set the entry expiration timeout. */
3158 if (entry_ptr -> protocol == NX_PROTOCOL_TCP)
3159 {
3160
3161 /* TCP session. */
3162 timeout = NX_NAT_TCP_SESSION_TIMEOUT;
3163 }
3164 else
3165 {
3166
3167 /* Non-TCP session. */
3168 timeout = NX_NAT_NON_TCP_SESSION_TIMEOUT;
3169 }
3170
3171 /* Create an entry with NAT translation for IP address/port. */
3172 status = _nx_nat_entry_create(nat_ptr, entry_ptr -> protocol,
3173 entry_ptr -> local_ip_address,
3174 entry_ptr -> peer_ip_address,
3175 entry_ptr -> local_port,
3176 entry_ptr -> external_port,
3177 entry_ptr -> peer_port,
3178 timeout,
3179 &record_entry);
3180
3181 /* Check for error. */
3182 if (status != NX_SUCCESS)
3183 {
3184
3185 /* Return error status. */
3186 return status;
3187 }
3188 }
3189
3190 /* Set the packet interface as global interface. */
3191 packet_ptr -> nx_packet_address.nx_packet_interface_ptr = &(nat_ptr -> nx_nat_ip_ptr -> nx_ip_interface[nat_ptr -> nx_nat_global_interface_index]);
3192
3193 /* Set the next hop address. */
3194 if(_nx_ip_route_find(nat_ptr -> nx_nat_ip_ptr, record_entry -> peer_ip_address, &packet_ptr -> nx_packet_address.nx_packet_interface_ptr, next_hop_address) != NX_SUCCESS)
3195 {
3196
3197 /* No suitable private interface configured. */
3198
3199 /* Return the error status. */
3200 return (NX_NAT_ROUTE_FIND_ERROR);
3201 }
3202
3203 /* Set the matched entry pointer. */
3204 *matched_entry_ptr = record_entry;
3205
3206 /* Return success. */
3207 return (NX_SUCCESS);
3208 }
3209
3210
3211 /**************************************************************************/
3212 /* */
3213 /* FUNCTION RELEASE */
3214 /* */
3215 /* _nx_nat_entry_create PORTABLE C */
3216 /* 6.1 */
3217 /* AUTHOR */
3218 /* */
3219 /* Yuxin Zhou, Microsoft Corporation */
3220 /* */
3221 /* DESCRIPTION */
3222 /* */
3223 /* This function dynamically creates a NAT translation table entry */
3224 /* and appends the entry to the translation list. */
3225 /* */
3226 /* INPUT */
3227 /* */
3228 /* nat_ptr Pointer to NAT instance */
3229 /* protocol Protocol of packets matching entry*/
3230 /* local_ip_address Entry's private IP address */
3231 /* peer_ip_address Entry's external host IP */
3232 /* local_port Entry's private port */
3233 /* external_port Entry's global port */
3234 /* peer_port Entry's external port (optional) */
3235 /* response_timeout Entry expiration timeout */
3236 /* match_entry_ptr Pointer to entry created */
3237 /* */
3238 /* OUTPUT */
3239 /* */
3240 /* status Actual completion status */
3241 /* NX_SUCCESS Successful completion status */
3242 /* NX_NAT_TRANSLATION_TABLE_FULL Table is full (max capacity) */
3243 /* NX_NAT_INVALID_TABLE_ENTRY Invalid criteria for table entry */
3244 /* */
3245 /* CALLS */
3246 /* */
3247 /* _nx_nat_entry_add Add entry to linked list of entries*/
3248 /* memset Clear specified area of memory */
3249 /* */
3250 /* CALLED BY */
3251 /* */
3252 /* _nx_nat_inbound_entry_find Find inbound entry in entry list */
3253 /* _nx_nat_outbound_entry_find Find outbound entry in entry list */
3254 /* */
3255 /* RELEASE HISTORY */
3256 /* */
3257 /* DATE NAME DESCRIPTION */
3258 /* */
3259 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3260 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3261 /* resulting in version 6.1 */
3262 /* */
3263 /**************************************************************************/
_nx_nat_entry_create(NX_NAT_DEVICE * nat_ptr,UCHAR protocol,ULONG local_ip_address,ULONG peer_ip_address,USHORT local_port,USHORT external_port,USHORT peer_port,ULONG response_timeout,NX_NAT_TRANSLATION_ENTRY ** match_entry_ptr)3264 static UINT _nx_nat_entry_create(NX_NAT_DEVICE *nat_ptr, UCHAR protocol,
3265 ULONG local_ip_address, ULONG peer_ip_address,
3266 USHORT local_port, USHORT external_port, USHORT peer_port,
3267 ULONG response_timeout, NX_NAT_TRANSLATION_ENTRY **match_entry_ptr)
3268 {
3269
3270 NX_NAT_TRANSLATION_ENTRY *insert_entry_ptr = NX_NULL;
3271
3272 #ifdef NX_NAT_ENABLE_REPLACEMENT
3273 NX_NAT_TRANSLATION_ENTRY *insert_previous_ptr = NX_NULL;
3274 NX_NAT_TRANSLATION_ENTRY *entry_ptr = NX_NULL;
3275 NX_NAT_TRANSLATION_ENTRY *previous_ptr = NX_NULL;
3276 #endif /* NX_NAT_ENABLE_REPLACEMENT */
3277
3278
3279 /* Initialize result to not found. */
3280 *match_entry_ptr = NX_NULL;
3281
3282 /* Perform some simple sanity checks on this entry. */
3283
3284 /* Was an invalid IP address submitted? */
3285 if ((peer_ip_address == 0x0) ||
3286 (local_ip_address == 0x0))
3287 {
3288
3289 return (NX_NAT_INVALID_ENTRY);
3290 }
3291
3292 /* Check available entries. */
3293 if (nat_ptr -> nx_nat_dynamic_available_entries)
3294 {
3295
3296 /* Get one available entry. */
3297 insert_entry_ptr = nat_ptr -> nx_nat_dynamic_available_entry_head;
3298
3299 /* Update the entry head. */
3300 nat_ptr -> nx_nat_dynamic_available_entry_head = insert_entry_ptr -> next_entry_ptr;
3301 }
3302 else
3303 {
3304 #ifdef NX_NAT_ENABLE_REPLACEMENT
3305
3306 /* Get a pointer to the start of the entries in the translation table. */
3307 entry_ptr = nat_ptr -> nx_nat_dynamic_active_entry_head;
3308
3309 /* Search the whole entry list to find the oldest non-TCP entry. */
3310 while (entry_ptr)
3311 {
3312
3313 /* Check the entry type and protocol. */
3314 if ((entry_ptr -> translation_type == NX_NAT_STATIC_ENTRY) || (entry_ptr -> protocol == NX_PROTOCOL_TCP))
3315 {
3316
3317 /* Ingore this entry, Get the next entry in the table. */
3318 previous_ptr = entry_ptr;
3319 entry_ptr = entry_ptr -> next_entry_ptr;
3320 continue;
3321 }
3322 else
3323 {
3324
3325 /* Check if set the insert_entry_ptr(oldest entry). */
3326 if (insert_entry_ptr == NX_NULL)
3327 {
3328
3329 /* Assume the first entry is the oldest entry. */
3330 insert_entry_ptr = entry_ptr;
3331 insert_previous_ptr = previous_ptr;
3332 }
3333 else
3334 {
3335
3336 /* Compare the timestamp. */
3337 if (((INT)insert_entry_ptr -> response_timestamp - (INT)entry_ptr -> response_timestamp) > 0)
3338 {
3339
3340 /* entry_ptr is an older entry, so update the insert_entry_ptr. */
3341 insert_entry_ptr = entry_ptr;
3342 insert_previous_ptr = previous_ptr;
3343 }
3344 }
3345
3346 /* Get the next entry in the table. */
3347 previous_ptr = entry_ptr;
3348 entry_ptr = entry_ptr -> next_entry_ptr;
3349 }
3350 }
3351
3352 /* Check if found the oldest non-TCP entry. */
3353 if (insert_entry_ptr)
3354 {
3355
3356 /* Yes, found it. Check if this is the first entry in the list. */
3357 if (insert_previous_ptr)
3358 {
3359
3360 /* It is not, so link the previous entry around the entry we are deleting. */
3361 insert_previous_ptr -> next_entry_ptr = insert_entry_ptr -> next_entry_ptr;
3362 }
3363 else
3364 {
3365
3366 /* It is the first entry, so set the next pointer as the starting translation table entry. */
3367 nat_ptr -> nx_nat_dynamic_active_entry_head = insert_entry_ptr -> next_entry_ptr;
3368 }
3369
3370 /* Update the entry count. */
3371 nat_ptr -> nx_nat_dynamic_active_entries --;
3372 nat_ptr -> nx_nat_dynamic_available_entries ++;
3373 }
3374 else
3375 {
3376 #endif /* NX_NAT_ENABLE_REPLACEMENT */
3377
3378 /* This service cache does not have room for the entry. */
3379 /* Invoke user-installed cache full notify function .*/
3380 if(nat_ptr -> nx_nat_cache_full_notify)
3381 {
3382
3383 /* Call the callback function. */
3384 (nat_ptr -> nx_nat_cache_full_notify)(nat_ptr);
3385 }
3386
3387 /* Return error status. */
3388 return (NX_NAT_CACHE_FULL);
3389
3390 #ifdef NX_NAT_ENABLE_REPLACEMENT
3391 }
3392 #endif /* NX_NAT_ENABLE_REPLACEMENT */
3393 }
3394
3395 /* Initialize the allocated memory to NULL. */
3396 memset(insert_entry_ptr, 0, sizeof(NX_NAT_TRANSLATION_ENTRY));
3397
3398 /* Assign the entry attributes. */
3399 insert_entry_ptr -> protocol = protocol;
3400 insert_entry_ptr -> local_ip_address = local_ip_address;
3401 insert_entry_ptr -> peer_ip_address = peer_ip_address;
3402 insert_entry_ptr -> local_port = local_port;
3403 insert_entry_ptr -> external_port = external_port;
3404 insert_entry_ptr -> peer_port = peer_port;
3405 insert_entry_ptr -> response_timeout = response_timeout;
3406
3407 /* Set the entry timestamp. */
3408 insert_entry_ptr -> response_timestamp = tx_time_get();
3409
3410 /* Set entry type to dynamically created. */
3411 insert_entry_ptr -> translation_type = NX_NAT_DYNAMIC_ENTRY;
3412
3413 /* Append to the table. */
3414 _nx_nat_entry_add(nat_ptr, insert_entry_ptr);
3415
3416 /* Set a pointer to the newly created entry. */
3417 *match_entry_ptr = insert_entry_ptr;
3418
3419 /* Return successful completion status. */
3420 return (NX_SUCCESS);
3421 }
3422
3423
3424 /**************************************************************************/
3425 /* */
3426 /* FUNCTION RELEASE */
3427 /* */
3428 /* _nx_nat_entry_add PORTABLE C */
3429 /* 6.1 */
3430 /* AUTHOR */
3431 /* */
3432 /* Yuxin Zhou, Microsoft Corporation */
3433 /* */
3434 /* DESCRIPTION */
3435 /* */
3436 /* This function adds a NAT translation entry to the NAT entry list */
3437 /* */
3438 /* INPUT */
3439 /* */
3440 /* nat_ptr Pointer to NAT instance */
3441 /* entry_ptr Pointer to NAT translation entry */
3442 /* */
3443 /* OUTPUT */
3444 /* */
3445 /* NX_SUCCESS Successful completion status */
3446 /* */
3447 /* CALLS */
3448 /* */
3449 /* None */
3450 /* */
3451 /* CALLED BY */
3452 /* */
3453 /* _nx_nat_inbound_entry_create Create inbound entry to NAT table */
3454 /* before starting the NAT server */
3455 /* _nx_nat_entry_create Create and add entry to NAT table */
3456 /* after starting the NAT server */
3457 /* */
3458 /* RELEASE HISTORY */
3459 /* */
3460 /* DATE NAME DESCRIPTION */
3461 /* */
3462 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3463 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3464 /* resulting in version 6.1 */
3465 /* */
3466 /**************************************************************************/
_nx_nat_entry_add(NX_NAT_DEVICE * nat_ptr,NX_NAT_TRANSLATION_ENTRY * entry_ptr)3467 static UINT _nx_nat_entry_add(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr)
3468 {
3469
3470
3471 /* Add this entry onto the table entry list. */
3472 entry_ptr -> next_entry_ptr = nat_ptr -> nx_nat_dynamic_active_entry_head;
3473 nat_ptr -> nx_nat_dynamic_active_entry_head = entry_ptr;
3474
3475 /* Update the entry count. */
3476 if (entry_ptr -> translation_type == NX_NAT_DYNAMIC_ENTRY)
3477 {
3478
3479 /* Update the entry count. */
3480 nat_ptr -> nx_nat_dynamic_active_entries ++;
3481 nat_ptr -> nx_nat_dynamic_available_entries --;
3482 }
3483 else
3484 nat_ptr -> nx_nat_static_active_entries ++;
3485
3486 /* Return success status. */
3487 return(NX_SUCCESS);
3488 }
3489
3490
3491 /**************************************************************************/
3492 /* */
3493 /* FUNCTION RELEASE */
3494 /* */
3495 /* _nx_nat_entry_find PORTABLE C */
3496 /* 6.1 */
3497 /* AUTHOR */
3498 /* */
3499 /* Yuxin Zhou, Microsoft Corporation */
3500 /* */
3501 /* DESCRIPTION */
3502 /* */
3503 /* This function attempts to find an entry in the NAT translation list */
3504 /* that matches the entry submitted by the caller. If none is found it*/
3505 /* returns a null pointer. There is an option to skip entries */
3506 /* designated for local hosts accepting packets from external hosts */
3507 /* (e.g. servers). */
3508 /* */
3509 /* INPUT */
3510 /* */
3511 /* nat_ptr Pointer to NAT server */
3512 /* entry_to_match Pointer to entry to match in the list */
3513 /* match_entry_ptr Pointer to matching entry in the list */
3514 /* direction Forward direction(inbound/outbound) */
3515 /* skip_inbound_init_entries Skip entries for local hosts allowing */
3516 /* initial packet from external source */
3517 /* */
3518 /* OUTPUT */
3519 /* */
3520 /* NX_SUCCESS Successful completion status */
3521 /* status Actual completion status */
3522 /* */
3523 /* CALLS */
3524 /* */
3525 /* tx_time_get Get the system time */
3526 /* */
3527 /* CALLED BY */
3528 /* */
3529 /* _nx_nat_inbound_entry_find Find inbound entry in entry list */
3530 /* _nx_nat_outbound_entry_find Find outbound entry in entry list */
3531 /* */
3532 /* RELEASE HISTORY */
3533 /* */
3534 /* DATE NAME DESCRIPTION */
3535 /* */
3536 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3537 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3538 /* resulting in version 6.1 */
3539 /* */
3540 /**************************************************************************/
_nx_nat_entry_find(NX_NAT_DEVICE * nat_ptr,NX_NAT_TRANSLATION_ENTRY * entry_to_match,NX_NAT_TRANSLATION_ENTRY ** match_entry_ptr,UCHAR direction,UINT skip_static_entries)3541 static VOID _nx_nat_entry_find(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *entry_to_match, NX_NAT_TRANSLATION_ENTRY **match_entry_ptr,
3542 UCHAR direction, UINT skip_static_entries)
3543 {
3544
3545 NX_NAT_TRANSLATION_ENTRY *entry_ptr;
3546 NX_NAT_TRANSLATION_ENTRY *previous_ptr;
3547
3548
3549 /* Initialize the search result to null (no match found). */
3550 *match_entry_ptr = 0x0;
3551
3552 /* Check the inbound entry. */
3553 if ((direction == NX_NAT_INBOUND_PACKET) &&
3554 (!entry_to_match -> peer_ip_address))
3555 {
3556
3557 /* Return. */
3558 return;
3559 }
3560
3561 /* Check the outbound entry. */
3562 if ((direction == NX_NAT_OUTBOUND_PACKET) &&
3563 ((!entry_to_match -> local_ip_address) || (!entry_to_match -> peer_ip_address)))
3564 {
3565
3566 /* Return. */
3567 return ;
3568 }
3569
3570 /* Initialize the previous pointer. */
3571 previous_ptr = NX_NULL;
3572
3573 /* Get a pointer to the start of the entries in the translation table. */
3574 entry_ptr = nat_ptr -> nx_nat_dynamic_active_entry_head;
3575
3576 /* Search the whole table until a match is found. */
3577 while (entry_ptr)
3578 {
3579
3580 /* Check the entry type, (e.g. accepts packets from external hosts) ?*/
3581 if ((entry_ptr -> translation_type == NX_NAT_STATIC_ENTRY) && (skip_static_entries == NX_TRUE))
3582 {
3583
3584 /* Set the previous entry pointer. */
3585 previous_ptr = entry_ptr;
3586
3587 /* Ingore the static entry, get the next entry in the table. */
3588 entry_ptr = entry_ptr -> next_entry_ptr;
3589
3590 continue;
3591 }
3592
3593 /* Do sender and entry protocols match? */
3594 if (entry_ptr -> protocol != entry_to_match -> protocol)
3595 {
3596
3597 /* Set the previous entry pointer. */
3598 previous_ptr = entry_ptr;
3599
3600 /* Get the next entry in the table. */
3601 entry_ptr = entry_ptr -> next_entry_ptr;
3602
3603 continue;
3604 }
3605
3606 /* Continue matching IP address and port criteria. */
3607
3608 /* Do external IP addresses, if specified, match? */
3609 if ((entry_ptr -> peer_ip_address) &&
3610 (entry_ptr -> peer_ip_address != entry_to_match -> peer_ip_address))
3611 {
3612
3613 /* Set the previous entry pointer. */
3614 previous_ptr = entry_ptr;
3615
3616 /* No, get the next entry. */
3617 entry_ptr = entry_ptr -> next_entry_ptr;
3618
3619 continue;
3620 }
3621
3622 /* Do external ports, if specified match? */
3623 if ((entry_ptr -> peer_port) &&
3624 (entry_ptr -> peer_port != entry_to_match -> peer_port))
3625 {
3626
3627 /* Set the previous entry pointer. */
3628 previous_ptr = entry_ptr;
3629
3630 /* No, get the next entry in the table. */
3631 entry_ptr = entry_ptr -> next_entry_ptr;
3632
3633 continue;
3634 }
3635
3636 /* Check the inbound entry. */
3637 if (direction == NX_NAT_INBOUND_PACKET)
3638 {
3639
3640 /* Does the inside host global port, if specified, match? */
3641 if ((entry_ptr -> external_port) &&
3642 (entry_ptr -> external_port != entry_to_match -> external_port))
3643 {
3644
3645 /* Set the previous entry pointer. */
3646 previous_ptr = entry_ptr;
3647
3648 /* No, get the next entry in the table. */
3649 entry_ptr = entry_ptr -> next_entry_ptr;
3650
3651 continue;
3652 }
3653 }
3654 else
3655 {
3656
3657 /* Do private inside IP addresses, if specified, match? */
3658 if ((entry_ptr -> local_ip_address) &&
3659 (entry_ptr -> local_ip_address != entry_to_match -> local_ip_address))
3660 {
3661
3662 /* Set the previous entry pointer. */
3663 previous_ptr = entry_ptr;
3664
3665 /* No, get the next entry in the table. */
3666 entry_ptr = entry_ptr -> next_entry_ptr;
3667
3668 continue;
3669 }
3670
3671 /* Does the inside host private port, if specified, match? */
3672 if ((entry_ptr -> local_port) &&
3673 (entry_ptr -> local_port != entry_to_match -> local_port))
3674 {
3675
3676 /* Set the previous entry pointer. */
3677 previous_ptr = entry_ptr;
3678
3679 /* No, get the next entry in the table. */
3680 entry_ptr = entry_ptr -> next_entry_ptr;
3681
3682 continue;
3683 }
3684 }
3685
3686 /* If we got this far, all criteria matched up. Set a pointer to
3687 this entry in the table. */
3688 *match_entry_ptr = entry_ptr;
3689
3690 /* The entry is active, reset the timeout to the present. */
3691 entry_ptr -> response_timestamp = tx_time_get();
3692
3693 /* Yes; check if this is the first entry in the list. */
3694 if (previous_ptr)
3695 {
3696
3697 /* It is not. Put this entry at the head of the list to improve searching effectiveness. */
3698 previous_ptr -> next_entry_ptr = entry_ptr -> next_entry_ptr;
3699 entry_ptr -> next_entry_ptr = nat_ptr -> nx_nat_dynamic_active_entry_head;
3700 nat_ptr -> nx_nat_dynamic_active_entry_head = entry_ptr;
3701 }
3702 break;
3703 }
3704 return;
3705 }
3706
3707
3708 /**************************************************************************/
3709 /* */
3710 /* FUNCTION RELEASE */
3711 /* */
3712 /* _nx_nat_entry_timeout_check PORTABLE C */
3713 /* 6.1 */
3714 /* AUTHOR */
3715 /* */
3716 /* Yuxin Zhou, Microsoft Corporation */
3717 /* */
3718 /* DESCRIPTION */
3719 /* */
3720 /* This function attempts to check the entry's timeout, and remove the */
3721 /* expiration entries from dynamic active translation list. */
3722 /* */
3723 /* INPUT */
3724 /* */
3725 /* nat_ptr Pointer to NAT server */
3726 /* */
3727 /* OUTPUT */
3728 /* */
3729 /* NX_SUCCESS Successful completion status */
3730 /* */
3731 /* CALLS */
3732 /* */
3733 /* tx_time_get Get the system time */
3734 /* */
3735 /* CALLED BY */
3736 /* */
3737 /* _nx_nat_inbound_entry_find Find inbound entry in entry list */
3738 /* _nx_nat_outbound_entry_find Find outbound entry in entry list */
3739 /* */
3740 /* RELEASE HISTORY */
3741 /* */
3742 /* DATE NAME DESCRIPTION */
3743 /* */
3744 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3745 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3746 /* resulting in version 6.1 */
3747 /* */
3748 /**************************************************************************/
_nx_nat_entry_timeout_check(NX_NAT_DEVICE * nat_ptr)3749 static VOID _nx_nat_entry_timeout_check(NX_NAT_DEVICE *nat_ptr)
3750 {
3751
3752 ULONG current_time;
3753 ULONG elapsed_time;
3754 NX_NAT_TRANSLATION_ENTRY *entry_ptr;
3755 NX_NAT_TRANSLATION_ENTRY *previous_ptr;
3756 NX_NAT_TRANSLATION_ENTRY *next_entry_ptr;
3757
3758
3759 /* Get the current time. */
3760 current_time = tx_time_get();
3761
3762 /* Get a pointer to the start of the entries in the translation table. */
3763 entry_ptr = nat_ptr -> nx_nat_dynamic_active_entry_head;
3764
3765 /* Initialize the previous pointer. */
3766 previous_ptr = NX_NULL;
3767
3768 /* Search thru the whole entry list. */
3769 while (entry_ptr)
3770 {
3771
3772 /* Set a pointer to the next entry in the table. */
3773 next_entry_ptr = entry_ptr -> next_entry_ptr;
3774
3775 /* Check the entry type and update the time. */
3776 if (entry_ptr -> translation_type == NX_NAT_DYNAMIC_ENTRY)
3777 {
3778
3779 /* Calculate the elapsed time. */
3780 elapsed_time = current_time - entry_ptr -> response_timestamp;
3781
3782 /* Update the time remaining. */
3783 if (elapsed_time >= entry_ptr -> response_timeout)
3784 {
3785
3786 /* Delete this entry from active entry list. */
3787
3788 /* Check if this is the first entry in the list). */
3789 if (previous_ptr)
3790 {
3791
3792 /* It is not, so link the previous entry around the entry we are deleting. */
3793 previous_ptr -> next_entry_ptr = next_entry_ptr;
3794 }
3795 else
3796 {
3797
3798 /* It is the first entry, so set the next pointer as the starting translation table entry. */
3799 nat_ptr -> nx_nat_dynamic_active_entry_head = next_entry_ptr;
3800 }
3801
3802 /* Add the entry onto available entry list. */
3803 entry_ptr -> next_entry_ptr = nat_ptr -> nx_nat_dynamic_available_entry_head;
3804 nat_ptr -> nx_nat_dynamic_available_entry_head = entry_ptr;
3805
3806 /* Update the entry count. */
3807 nat_ptr -> nx_nat_dynamic_active_entries --;
3808 nat_ptr -> nx_nat_dynamic_available_entries ++;
3809 }
3810 else
3811 {
3812
3813 /* Set the previous entry. */
3814 previous_ptr = entry_ptr;
3815 }
3816 }
3817 else
3818 {
3819
3820 /* Set the previous entry. */
3821 previous_ptr = entry_ptr;
3822 }
3823
3824 /* Get the next entry in the table. */
3825 entry_ptr = next_entry_ptr;
3826 }
3827
3828 return;
3829 }
3830
3831
3832 /**************************************************************************/
3833 /* */
3834 /* FUNCTION RELEASE */
3835 /* */
3836 /* _nx_nat_utility_get_destination_port PORTABLE C */
3837 /* 6.1 */
3838 /* AUTHOR */
3839 /* */
3840 /* Yuxin Zhou, Microsoft Corporation */
3841 /* */
3842 /* DESCRIPTION */
3843 /* */
3844 /* This function extracts the destination port from the packet's */
3845 /* protocol header. In the case of ICMP packets, it extracts the ICMP */
3846 /* header identifier (ID) instead. */
3847 /* */
3848 /* INPUT */
3849 /* */
3850 /* packet_ptr Pointer to packet with destination port */
3851 /* protocol Packet protocol (TCP, UDP etc) */
3852 /* peer_port Pointer to external (destination) port */
3853 /* */
3854 /* OUTPUT */
3855 /* */
3856 /* NX_SUCCESS Successful completion status */
3857 /* */
3858 /* CALLS */
3859 /* */
3860 /* _nx_nat_packet_is_icmp_error_message */
3861 /* Indicate if ICMP packet is query or */
3862 /* error message packet */
3863 /* */
3864 /* CALLED BY */
3865 /* */
3866 /* _nx_nat_inbound_entry_find Find inbound entry in entry list */
3867 /* _nx_nat_outbound_entry_find Find outbound entry in entry list */
3868 /* */
3869 /* RELEASE HISTORY */
3870 /* */
3871 /* DATE NAME DESCRIPTION */
3872 /* */
3873 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3874 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3875 /* resulting in version 6.1 */
3876 /* */
3877 /**************************************************************************/
_nx_nat_utility_get_destination_port(NX_PACKET * packet_ptr,UCHAR protocol,USHORT * peer_port)3878 static UINT _nx_nat_utility_get_destination_port(NX_PACKET *packet_ptr, UCHAR protocol, USHORT *peer_port)
3879 {
3880
3881 NX_TCP_HEADER *tcp_header_ptr;
3882 NX_UDP_HEADER *udp_header_ptr;
3883 NX_ICMP_HEADER *icmp_header_ptr;
3884 UINT is_icmp_error_msg;
3885
3886
3887 /* Is this a TCP packet? */
3888 if (protocol == NX_PROTOCOL_TCP)
3889 {
3890
3891 /* Pickup the pointer to the head of the TCP packet. */
3892 tcp_header_ptr = (NX_TCP_HEADER *)(packet_ptr -> nx_packet_prepend_ptr);
3893
3894 /* Pickup the destination TCP port. */
3895 *peer_port = (USHORT) (tcp_header_ptr -> nx_tcp_header_word_0 & NX_LOWER_16_MASK);
3896 }
3897 /* Is this a UDP packet? */
3898 else if (protocol == NX_PROTOCOL_UDP)
3899 {
3900
3901 /* Pickup the pointer to the head of the UDP packet. */
3902 udp_header_ptr = (NX_UDP_HEADER *)(packet_ptr -> nx_packet_prepend_ptr);
3903
3904 /* Pickup the destination UDP port. */
3905 *peer_port = (USHORT) (udp_header_ptr -> nx_udp_header_word_0 & NX_LOWER_16_MASK);
3906 }
3907 /* Is this an ICMP packet? */
3908 else if (protocol == NX_PROTOCOL_ICMP)
3909 {
3910
3911 /* Determin type of ICMP message. */
3912 _nx_nat_packet_is_icmp_error_message(packet_ptr, &is_icmp_error_msg);
3913
3914 /* Is this an ICMP error message? */
3915 if (is_icmp_error_msg )
3916 {
3917
3918 /* Yes, these don't have query ID fields. */
3919 *peer_port = 0;
3920 }
3921 else
3922 {
3923
3924 /* Setup the pointer to the ICMP header located in the data area after the IP header. */
3925 icmp_header_ptr = (NX_ICMP_HEADER *) (packet_ptr -> nx_packet_prepend_ptr);
3926
3927 /* Pickup the ICMP identifier which we will call the 'source port'. */
3928 *peer_port = (USHORT) (icmp_header_ptr -> nx_icmp_header_word_1 >> NX_SHIFT_BY_16);
3929 }
3930 }
3931 else
3932 {
3933
3934 /* Unknown or unsupported packet protocol. */
3935 *peer_port = 0;
3936 }
3937
3938 return NX_SUCCESS;
3939 }
3940
3941
3942 /**************************************************************************/
3943 /* */
3944 /* FUNCTION RELEASE */
3945 /* */
3946 /* _nx_nat_utility_get_source_port PORTABLE C */
3947 /* 6.1 */
3948 /* AUTHOR */
3949 /* */
3950 /* Yuxin Zhou, Microsoft Corporation */
3951 /* */
3952 /* DESCRIPTION */
3953 /* */
3954 /* This function extracts the source port from the packet's protocol */
3955 /* header. In the case of ICMP packets, it extracts the query identifier*/
3956 /* (ID) instead. */
3957 /* */
3958 /* INPUT */
3959 /* */
3960 /* packet_ptr Pointer to packet to get source port */
3961 /* protocol Packet protocol (TCP, UDP etc) */
3962 /* source_port Pointer to packet source port */
3963 /* */
3964 /* OUTPUT */
3965 /* */
3966 /* NX_SUCCESS Successful completion status */
3967 /* */
3968 /* CALLS */
3969 /* */
3970 /* _nx_nat_packet_is_icmp_error_message */
3971 /* Indicate if ICMP packet is query or */
3972 /* error message ICMP packet */
3973 /* */
3974 /* CALLED BY */
3975 /* */
3976 /* _nx_nat_inbound_entry_find Find inbound entry in entry list */
3977 /* _nx_nat_outbound_entry_find Find outbound entry in entry list */
3978 /* */
3979 /* RELEASE HISTORY */
3980 /* */
3981 /* DATE NAME DESCRIPTION */
3982 /* */
3983 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3984 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3985 /* resulting in version 6.1 */
3986 /* */
3987 /**************************************************************************/
_nx_nat_utility_get_source_port(NX_PACKET * packet_ptr,UCHAR protocol,USHORT * source_port)3988 static UINT _nx_nat_utility_get_source_port(NX_PACKET *packet_ptr, UCHAR protocol, USHORT *source_port)
3989 {
3990
3991 NX_TCP_HEADER *tcp_header_ptr;
3992 NX_UDP_HEADER *udp_header_ptr;
3993 NX_ICMP_HEADER *icmp_header_ptr;
3994 UINT is_icmp_error_msg;
3995
3996 if (protocol == NX_PROTOCOL_TCP)
3997 {
3998
3999 /* Pickup the pointer to the head of the TCP packet. */
4000 tcp_header_ptr = (NX_TCP_HEADER *)(packet_ptr -> nx_packet_prepend_ptr);
4001
4002 /* Pickup the source TCP port. */
4003 *source_port = (USHORT) (tcp_header_ptr -> nx_tcp_header_word_0 >> NX_SHIFT_BY_16);
4004 }
4005 else if (protocol == NX_PROTOCOL_UDP)
4006 {
4007
4008 /* Pickup the pointer to the head of the UDP packet. */
4009 udp_header_ptr = (NX_UDP_HEADER *)(packet_ptr -> nx_packet_prepend_ptr);
4010
4011 /* Pickup the source UDP port. */
4012 *source_port = (USHORT) (udp_header_ptr -> nx_udp_header_word_0 >> NX_SHIFT_BY_16);
4013 }
4014 else if (protocol == NX_PROTOCOL_ICMP)
4015 {
4016
4017 /* Determine type of ICMP message. */
4018 _nx_nat_packet_is_icmp_error_message(packet_ptr, &is_icmp_error_msg);
4019
4020 /* Is this an ICMP error message? */
4021 if (is_icmp_error_msg )
4022 {
4023
4024 /* Yes, return a zero query ID (error messages have no Query ID). */
4025 *source_port = 0;
4026 }
4027 else
4028 {
4029
4030 /* Setup the pointer to the ICMP header located in the data area after the IP header. */
4031 icmp_header_ptr = (NX_ICMP_HEADER *) (packet_ptr -> nx_packet_prepend_ptr);
4032
4033 /* Pickup the ICMP Query ID which is used in place of a source port. */
4034 *source_port = (USHORT)(icmp_header_ptr -> nx_icmp_header_word_1 >> NX_SHIFT_BY_16);
4035 }
4036 }
4037 else
4038 /* Unknown or unsupported protocol. */
4039 *source_port = 0;
4040
4041 return NX_SUCCESS;
4042 }
4043
4044
4045 /**************************************************************************/
4046 /* */
4047 /* FUNCTION RELEASE */
4048 /* */
4049 /* _nx_nat_find_available_port PORTABLE C */
4050 /* 6.1 */
4051 /* AUTHOR */
4052 /* */
4053 /* Yuxin Zhou, Microsoft Corporation */
4054 /* */
4055 /* DESCRIPTION */
4056 /* */
4057 /* This function finds an available a ICMP query identifier (ID) or */
4058 /* or TCP/UDP port when NAT is configured to share a global IP address */
4059 /* among its local hosts and consequently must use the query ID/port */
4060 /* field to uniquely identify. */
4061 /* */
4062 /* INPUT */
4063 /* */
4064 /* nat_ptr Pointer to NAT instance */
4065 /* protocol Network protocol(TCP, UDP, ICMP) */
4066 /* port Pointer to an unused port */
4067 /* */
4068 /* OUTPUT */
4069 /* */
4070 /* NX_SUCCESS Successful completion status */
4071 /* NX_NAT_NO_FREE_PORT_AVAILABLE No free port found status */
4072 /* status Actual completion status */
4073 /* */
4074 /* CALLS */
4075 /* */
4076 /* None */
4077 /* */
4078 /* CALLED BY */
4079 /* */
4080 /* _nx_nat_outbound_entry_find Find outbound entry in entry list */
4081 /* */
4082 /* RELEASE HISTORY */
4083 /* */
4084 /* DATE NAME DESCRIPTION */
4085 /* */
4086 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4087 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4088 /* resulting in version 6.1 */
4089 /* */
4090 /**************************************************************************/
_nx_nat_find_available_port(NX_NAT_DEVICE * nat_ptr,UCHAR protocol,USHORT * port)4091 static UINT _nx_nat_find_available_port(NX_NAT_DEVICE *nat_ptr, UCHAR protocol, USHORT *port)
4092 {
4093
4094 UINT bound;
4095 USHORT start_port;
4096 USHORT end_port;
4097 NX_NAT_TRANSLATION_ENTRY *entry_ptr;
4098
4099
4100 /* Start at the lowest of number for translated query ID/port for NAT. */
4101 if (protocol == NX_PROTOCOL_TCP)
4102 {
4103 start_port = NX_NAT_START_TCP_PORT;
4104 end_port = NX_NAT_END_TCP_PORT;
4105 }
4106 else if(protocol == NX_PROTOCOL_UDP)
4107 {
4108 start_port = NX_NAT_START_UDP_PORT;
4109 end_port = NX_NAT_END_UDP_PORT;
4110 }
4111 else
4112 {
4113 start_port = NX_NAT_START_ICMP_QUERY_ID;
4114 end_port = NX_NAT_END_ICMP_QUERY_ID;
4115 }
4116
4117 /* Set the start port. */
4118 *port = start_port;
4119
4120 /* Search for a Query ID not found in the translation table. */
4121 while(*port < end_port)
4122 {
4123
4124 /* Initialize the bound flag. */
4125 bound = NX_FALSE;
4126
4127 /* Serach dynamic entries. */
4128 entry_ptr = nat_ptr -> nx_nat_dynamic_active_entry_head;
4129
4130 /* Loop through the whole translation table. */
4131 while(entry_ptr)
4132 {
4133
4134 /* Check the protocol. */
4135 if (entry_ptr -> protocol == protocol)
4136 {
4137
4138 /* Does this entry have a matching port ID. */
4139 if (entry_ptr -> external_port == *port)
4140 {
4141
4142 /* Set the flag so we can abort the current search. */
4143 bound = NX_TRUE;
4144 break;
4145 }
4146 }
4147
4148 /* Get the next entry in the table. */
4149 entry_ptr = entry_ptr -> next_entry_ptr;
4150 }
4151
4152 /* Check if we got through the entire table with no bound port. */
4153 if ((bound == NX_FALSE) &&
4154 ((protocol == NX_PROTOCOL_TCP) || (protocol == NX_PROTOCOL_UDP)))
4155 {
4156
4157 /* Yes, check the NetXDuo TCP/UDP socket. */
4158 bound = _nx_nat_socket_port_verify(nat_ptr -> nx_nat_ip_ptr, protocol, *port);
4159 }
4160
4161 /* Check if we found a socket with a matching port. */
4162 if (bound == NX_FALSE)
4163 {
4164
4165 /* We did not. OK to use this port. */
4166 return NX_SUCCESS;
4167 }
4168
4169 /* Found a match. This port is not available. */
4170
4171 /* Bump the port up one. */
4172 (*port)++;
4173 }
4174
4175 /* If we got here we could not find a free port. */
4176 return (NX_NAT_NO_FREE_PORT_AVAILABLE);
4177 }
4178
4179
4180 /**************************************************************************/
4181 /* */
4182 /* FUNCTION RELEASE */
4183 /* */
4184 /* _nx_nat_entry_port_verify PORTABLE C */
4185 /* 6.1 */
4186 /* AUTHOR */
4187 /* */
4188 /* Yuxin Zhou, Microsoft Corporation */
4189 /* */
4190 /* DESCRIPTION */
4191 /* */
4192 /* This function verifies whether the supplied port is bound. lookup */
4193 /* all NAT translation entries, If same ports are found, return */
4194 /* NX_TRUE, else return NX_FALSE. */
4195 /* */
4196 /* INPUT */
4197 /* */
4198 /* ip_ptr IP instance pointer */
4199 /* protocol Protocol */
4200 /* port Port */
4201 /* */
4202 /* OUTPUT */
4203 /* */
4204 /* bound Completion status */
4205 /* NX_TRUE: port is bound */
4206 /* NX_FALSE: port is not bound */
4207 /* */
4208 /* CALLS */
4209 /* */
4210 /* none */
4211 /* */
4212 /* CALLED BY */
4213 /* */
4214 /* Application Code */
4215 /* */
4216 /* RELEASE HISTORY */
4217 /* */
4218 /* DATE NAME DESCRIPTION */
4219 /* */
4220 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4221 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4222 /* resulting in version 6.1 */
4223 /* */
4224 /**************************************************************************/
_nx_nat_entry_port_verify(NX_IP * ip_ptr,UINT protocol,UINT port)4225 static UINT _nx_nat_entry_port_verify(NX_IP *ip_ptr, UINT protocol, UINT port)
4226 {
4227
4228 UINT bound;
4229 NX_NAT_TRANSLATION_ENTRY *entry_ptr;
4230
4231 NX_PARAMETER_NOT_USED(ip_ptr);
4232
4233 /* Initialize the return value. */
4234 bound = NX_FALSE;
4235
4236 /* Serach dynamic entries. */
4237 entry_ptr = nat_server_ptr -> nx_nat_dynamic_active_entry_head;
4238
4239 /* Loop through the whole translation table. */
4240 while(entry_ptr)
4241 {
4242
4243 /* Check the protocol. */
4244 if (entry_ptr -> protocol == protocol)
4245 {
4246
4247 /* Does this entry have a matching port ID. */
4248 if (entry_ptr -> external_port == port)
4249 {
4250
4251 /* Set the flag so we can abort the current search. */
4252 bound = NX_TRUE;
4253 break;
4254 }
4255 }
4256
4257 /* Get the next entry in the table. */
4258 entry_ptr = entry_ptr -> next_entry_ptr;
4259 }
4260
4261 /* Return status to the caller. */
4262 return(bound);
4263 }
4264
4265
4266 /**************************************************************************/
4267 /* */
4268 /* FUNCTION RELEASE */
4269 /* */
4270 /* _nx_nat_socket_port_verify PORTABLE C */
4271 /* 6.1 */
4272 /* AUTHOR */
4273 /* */
4274 /* Yuxin Zhou, Microsoft Corporation */
4275 /* */
4276 /* DESCRIPTION */
4277 /* */
4278 /* This function verifies whether the supplied port is bound. Search */
4279 /* all TCP/UDP sockets, and if the port is found, return NX_TRUE, */
4280 /* else return NX_TRUE. */
4281 /* */
4282 /* INPUT */
4283 /* */
4284 /* ip_ptr IP instance pointer */
4285 /* protocol Protocol */
4286 /* port Port */
4287 /* */
4288 /* OUTPUT */
4289 /* */
4290 /* bound Completion status */
4291 /* NX_TRUE: port is bound */
4292 /* NX_FALSE: port is not bound */
4293 /* */
4294 /* CALLS */
4295 /* */
4296 /* none */
4297 /* */
4298 /* CALLED BY */
4299 /* */
4300 /* Application Code */
4301 /* */
4302 /* RELEASE HISTORY */
4303 /* */
4304 /* DATE NAME DESCRIPTION */
4305 /* */
4306 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4307 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4308 /* resulting in version 6.1 */
4309 /* */
4310 /**************************************************************************/
_nx_nat_socket_port_verify(NX_IP * ip_ptr,UINT protocol,UINT port)4311 static UINT _nx_nat_socket_port_verify(NX_IP *ip_ptr, UINT protocol, UINT port)
4312 {
4313
4314 UINT index;
4315 UINT bound;
4316 NX_TCP_SOCKET *tcp_search_ptr;
4317 NX_TCP_SOCKET *tcp_end_ptr;
4318 NX_UDP_SOCKET *udp_search_ptr;
4319 NX_UDP_SOCKET *udp_end_ptr;
4320
4321
4322 /* Initialize the return value. */
4323 bound = NX_FALSE;
4324
4325 /* Check the protocol. */
4326 if (protocol == NX_PROTOCOL_TCP)
4327 {
4328
4329 /* Calculate the hash index in the TCP port array of the associated IP instance. */
4330 index = (UINT) ((port + (port >> 8)) & NX_TCP_PORT_TABLE_MASK);
4331
4332 /* Pickup the head of the TCP ports bound list. */
4333 tcp_search_ptr = ip_ptr -> nx_ip_tcp_port_table[index];
4334
4335 /* Determine if we need to perform a list search. */
4336 if (tcp_search_ptr)
4337 {
4338
4339 /* Walk through the circular list of UDP sockets that are already bound. */
4340 tcp_end_ptr = tcp_search_ptr;
4341 do
4342 {
4343
4344 /* Determine if this entry is the same as the requested port. */
4345 if (tcp_search_ptr -> nx_tcp_socket_port == port)
4346 {
4347
4348 /* Yes, the port has already been bound. */
4349 bound = NX_TRUE;
4350 break;
4351 }
4352
4353 /* Move to the next entry in the list. */
4354 tcp_search_ptr = tcp_search_ptr -> nx_tcp_socket_bound_next;
4355
4356 } while (tcp_search_ptr != tcp_end_ptr);
4357 }
4358 }
4359 else
4360 {
4361
4362 /* Calculate the hash index in the UDP port array of the associated IP instance. */
4363 index = (UINT) ((port + (port >> 8)) & NX_UDP_PORT_TABLE_MASK);
4364
4365 /* Pickup the head of the UDP ports bound list. */
4366 udp_search_ptr = ip_ptr -> nx_ip_udp_port_table[index];
4367
4368 /* Determine if we need to perform a list search. */
4369 if (udp_search_ptr)
4370 {
4371
4372 /* Walk through the circular list of UDP sockets that are already bound. */
4373 udp_end_ptr = udp_search_ptr;
4374 do
4375 {
4376
4377 /* Determine if this entry is the same as the requested port. */
4378 if (udp_search_ptr -> nx_udp_socket_port == port)
4379 {
4380
4381 /* Yes, the port has already been bound. */
4382 bound = NX_TRUE;
4383 break;
4384 }
4385
4386 /* Move to the next entry in the list. */
4387 udp_search_ptr = udp_search_ptr -> nx_udp_socket_bound_next;
4388
4389 } while (udp_search_ptr != udp_end_ptr);
4390 }
4391 }
4392
4393 /* Return success to the caller. */
4394 return(bound);
4395 }
4396
4397
4398 /**************************************************************************/
4399 /* */
4400 /* FUNCTION RELEASE */
4401 /* */
4402 /* _nx_nat_packet_is_icmp_error_message PORTABLE C */
4403 /* 6.1 */
4404 /* AUTHOR */
4405 /* */
4406 /* Yuxin Zhou, Microsoft Corporation */
4407 /* */
4408 /* DESCRIPTION */
4409 /* */
4410 /* This function determines if an ICMP packet is a query message or an */
4411 /* error message. */
4412 /* */
4413 /* INPUT */
4414 /* */
4415 /* packet_ptr Pointer to ICMP packet to parse */
4416 /* is_icmp_error_msg Indicates if packet is an error */
4417 /* message packet */
4418 /* OUTPUT */
4419 /* */
4420 /* NX_SUCCESS Successful completion status */
4421 /* */
4422 /* CALLS */
4423 /* */
4424 /* None */
4425 /* */
4426 /* CALLED BY */
4427 /* */
4428 /* _nx_nat_process_inbound_ICMP_packet Forward inbound ICMP packets */
4429 /* _nx_nat_process_outbound_ICMP_packet Forward outbound ICMP packets */
4430 /* _nx_nat_utility_get_source_port Extract source port from header*/
4431 /* _nx_nat_utility_get_destination_port Extract destination port from */
4432 /* header */
4433 /* */
4434 /* RELEASE HISTORY */
4435 /* */
4436 /* DATE NAME DESCRIPTION */
4437 /* */
4438 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4439 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4440 /* resulting in version 6.1 */
4441 /* */
4442 /**************************************************************************/
_nx_nat_packet_is_icmp_error_message(NX_PACKET * packet_ptr,UINT * is_icmp_error_msg)4443 static UINT _nx_nat_packet_is_icmp_error_message(NX_PACKET *packet_ptr, UINT *is_icmp_error_msg)
4444 {
4445
4446 UINT type;
4447 UINT protocol;
4448 NX_IPV4_HEADER *ip_header_ptr;
4449 NX_ICMP_HEADER *icmp_header_ptr;
4450
4451
4452 /* Initialize the result to non error message type. */
4453 *is_icmp_error_msg = NX_FALSE;
4454
4455 /* Set up an IP header pointer to the packet. */
4456 ip_header_ptr = (NX_IPV4_HEADER *) (packet_ptr -> nx_packet_prepend_ptr - sizeof(NX_IPV4_HEADER));
4457
4458 /* Set up an ICMP header pointer to the packet. */
4459 icmp_header_ptr = (NX_ICMP_HEADER *) (packet_ptr -> nx_packet_prepend_ptr);
4460
4461 /* Determine what protocol the current IP datagram is. */
4462 protocol = (ip_header_ptr -> nx_ip_header_word_2 >> 16) & 0xFF;
4463
4464 /* Is this an ICMP packet? */
4465 if (protocol == NX_PROTOCOL_ICMP)
4466 {
4467
4468 /* Extract the ICMP type and code. */
4469 type = icmp_header_ptr -> nx_icmp_header_word_0 >> 24;
4470
4471 /* Determine if this is an error message. */
4472 if (type != NX_ICMP_ECHO_REPLY_TYPE &&
4473 type != NX_ICMP_ECHO_REQUEST_TYPE &&
4474 type < NX_ICMP_TIMESTAMP_REQ_TYPE)
4475 {
4476
4477 /* It is. Set the flag to true. */
4478 *is_icmp_error_msg = NX_TRUE;
4479 }
4480 }
4481
4482 /* Return successful completion status. */
4483 return NX_SUCCESS;
4484 }
4485
4486
4487 /**************************************************************************/
4488 /* */
4489 /* FUNCTION RELEASE */
4490 /* */
4491 /* _nx_nat_checksum_adjust PORTABLE C */
4492 /* 6.1 */
4493 /* AUTHOR */
4494 /* */
4495 /* Yuxin Zhou, Microsoft Corporation */
4496 /* */
4497 /* DESCRIPTION */
4498 /* */
4499 /* This function is an optimization for recomputing a checksum by just */
4500 /* computing the difference where a small amount of data has changed. */
4501 /* NAT uses this optimization when, for example, it is only changing an */
4502 /* IP address or port. */
4503 /* */
4504 /* INPUT */
4505 /* old_checksum Pointer to the old checksum */
4506 /* old_data Pointer to the data being changed*/
4507 /* new_data Pointer to new data replacing the*/
4508 /* old data */
4509 /* data_adjustment_length Size of data being changed */
4510 /* adjusted_checksum Pointer to the updated checksum */
4511 /* */
4512 /* OUTPUT */
4513 /* */
4514 /* NX_SUCCESS Successful completion status */
4515 /* */
4516 /* CALLS */
4517 /* */
4518 /* None */
4519 /* */
4520 /* CALLED BY */
4521 /* */
4522 /* _nx_nat_process_inbound_TCP_packet Send TCP packet to local host */
4523 /* _nx_nat_process_inbound_UDP_packet Send UDP packet to local host */
4524 /* _nx_nat_process_inbound_ICMP_packet Send ICMP packet to local host */
4525 /* _nx_nat_process_outbound_TCP_packet Send TCP packet to external host */
4526 /* _nx_nat_process_outbound_UDP_packet Send UDP packet to external host */
4527 /* _nx_nat_process_outbound_ICMP_packet Send ICMP packet to external host*/
4528 /* */
4529 /* RELEASE HISTORY */
4530 /* */
4531 /* DATE NAME DESCRIPTION */
4532 /* */
4533 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4534 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4535 /* resulting in version 6.1 */
4536 /* */
4537 /**************************************************************************/
_nx_nat_checksum_adjust(UCHAR * checksum,UCHAR * old_data,INT old_data_length,UCHAR * new_data,INT new_data_length)4538 static VOID _nx_nat_checksum_adjust(UCHAR *checksum, UCHAR *old_data, INT old_data_length, UCHAR *new_data, INT new_data_length)
4539 {
4540
4541 LONG x, old_value, new_value;
4542 INT i,j;
4543
4544 #ifdef NX_LITTLE_ENDIAN
4545 i = 1;
4546 j = 0;
4547 #else
4548 i = 0;
4549 j = 1;
4550 #endif
4551
4552 /* Checksum Adjustment, RFC 3022, Section 4.2, Page 9. */
4553
4554 /* Get the old checksum. */
4555 x = checksum[i] * 256 + checksum[j];
4556 x = ~x & 0xFFFF;
4557
4558 /* Update the checksum for old data. */
4559 while (old_data_length)
4560 {
4561
4562 /* Get the old data. */
4563 old_value = old_data[i] * 256 + old_data[j];
4564
4565 /* Update the old data pointer. */
4566 old_data += 2;
4567
4568 /* Update the checksum. */
4569 x -= old_value & 0xFFFF;
4570
4571 /* Check the value. */
4572 if (x <= 0)
4573 {
4574
4575 /* Update the value. */
4576 x --;
4577 x &= 0xFFFF;
4578 }
4579
4580 /* Update the old data length. */
4581 old_data_length -= 2;
4582 }
4583
4584 /* Update the checksum for new data. */
4585 while (new_data_length)
4586 {
4587
4588 /* Get the new data. */
4589 new_value = new_data[i] * 256 + new_data[j];
4590
4591 /* Update the new data pointer. */
4592 new_data += 2;
4593
4594 /* Update the checksum. */
4595 x += new_value & 0xFFFF;
4596
4597 /* Check the value. */
4598 if (x & 0x10000)
4599 {
4600
4601 /* Update the value. */
4602 x ++;
4603 x &= 0xFFFF;
4604 }
4605
4606 /* Update the new data length. */
4607 new_data_length -= 2;
4608 }
4609
4610 /* Update the value. */
4611 x = ~x & 0xFFFF;
4612
4613 /* Update the checksum. */
4614 checksum[i] = (UCHAR)(x /256);
4615 checksum[j] = (UCHAR)(x & 0xFF);
4616
4617 /* Return. */
4618 return;
4619 }
4620 #endif
4621