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