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.1 */
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 /* */
1168 /**************************************************************************/
_nx_nat_process_packet(NX_IP * ip_ptr,NX_PACKET * packet_ptr,UINT packet_process)1169 static UINT _nx_nat_process_packet(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT packet_process)
1170 {
1171
1172 UINT status;
1173 UINT protocol;
1174 ULONG header_size = sizeof(NX_IPV4_HEADER);
1175 UINT global_interface_index;
1176 ULONG next_hop_address;
1177 NX_IPV4_HEADER *ip_header_ptr;
1178 NX_INTERFACE *interface_ptr;
1179
1180
1181 /* Check the NAT's IP instance. */
1182 if (nat_server_ptr -> nx_nat_ip_ptr != ip_ptr)
1183 {
1184
1185 /* Let IP packet receive process this packet. */
1186 return (NX_FALSE);
1187 }
1188
1189 /* Pickup the packet header. */
1190 ip_header_ptr = (NX_IPV4_HEADER *) packet_ptr -> nx_packet_prepend_ptr;
1191
1192 /* Determine what protocol the current IP datagram is. */
1193 protocol = (ip_header_ptr -> nx_ip_header_word_2 >> 16) & 0xFF;
1194
1195 /* Check the protocol. */
1196 if ((protocol != NX_PROTOCOL_ICMP) && (protocol != NX_PROTOCOL_UDP) && (protocol != NX_PROTOCOL_TCP))
1197 {
1198
1199 /* Let IP packet receive process this packet. */
1200 return (NX_FALSE);
1201 }
1202
1203 #ifndef NX_DISABLE_RX_SIZE_CHECKING
1204 /* Check the next protocol. */
1205 if (protocol == NX_PROTOCOL_ICMP)
1206 {
1207 header_size += sizeof(NX_ICMP_HEADER);
1208 }
1209 else if (protocol == NX_PROTOCOL_UDP)
1210 {
1211 header_size += sizeof(NX_UDP_HEADER);
1212 }
1213 else
1214 {
1215 header_size += sizeof(NX_TCP_HEADER);
1216 }
1217
1218 /* Check for valid packet length. */
1219 if (packet_ptr -> nx_packet_length < header_size)
1220 {
1221
1222 #ifndef NX_DISABLE_IP_INFO
1223 /* Increment the IP invalid packet error. */
1224 ip_ptr -> nx_ip_invalid_packets++;
1225
1226 /* Increment the IP receive packets dropped count. */
1227 ip_ptr -> nx_ip_receive_packets_dropped++;
1228 #endif
1229
1230 /* Invalid packet length, just release it. */
1231 _nx_packet_release(packet_ptr);
1232
1233 /* Return NX_TRUE to indicate this packet has been processed. */
1234 return (NX_TRUE);
1235 }
1236 #endif /* NX_DISABLE_RX_SIZE_CHECKING */
1237
1238 /* Set the packet interface pointer and NAT's global interface index. */
1239 interface_ptr = packet_ptr -> nx_packet_address.nx_packet_interface_ptr;
1240 global_interface_index = nat_server_ptr -> nx_nat_global_interface_index;
1241
1242 /* Check if the direction of the translation is inbound. */
1243 if (interface_ptr == &(ip_ptr -> nx_ip_interface[global_interface_index]))
1244 {
1245
1246 /* Yes, this packet is received on NAT's external interface (an inbound packet). */
1247
1248 /* Check the destination ip address against NAT's external IP address. */
1249 if (ip_header_ptr -> nx_ip_header_destination_ip != interface_ptr -> nx_interface_ip_address)
1250 {
1251
1252 /* NAT cannot process this packet. Let IP packet receive process this packet. */
1253 return (NX_FALSE);
1254 }
1255
1256 /* Check if the caller wants NAT to process this packet. */
1257 if (packet_process == NX_TRUE)
1258 {
1259
1260 #ifndef NX_DISABLE_NAT_INFO
1261 /* Yes, so update the count. */
1262 nat_server_ptr -> forwarded_packets_received ++;
1263 #endif
1264
1265 /* Try to deliver the packet to the local host. */
1266 status = _nx_nat_process_inbound_packet(nat_server_ptr, packet_ptr);
1267
1268 /* Check the status. */
1269 if (status == NX_NAT_PACKET_CONSUMED_FAILED)
1270 {
1271
1272 /* Let IP packet receive process this packet. */
1273 return (NX_FALSE);
1274 }
1275 }
1276 }
1277 else
1278 {
1279
1280 /* Check the destination ip address. */
1281 if (
1282
1283 /* Check for zero address. */
1284 (ip_header_ptr -> nx_ip_header_destination_ip == 0) ||
1285
1286 /* Check for limited broadcast. */
1287 (ip_header_ptr -> nx_ip_header_destination_ip == NX_IP_LIMITED_BROADCAST) ||
1288
1289 /* Check for multicast address*/
1290 ((ip_header_ptr -> nx_ip_header_destination_ip & NX_IP_CLASS_D_MASK) == NX_IP_CLASS_D_TYPE) ||
1291
1292 /* Check for loopback address. */
1293 ((ip_header_ptr -> nx_ip_header_destination_ip >= NX_IP_LOOPBACK_FIRST) &&
1294 (ip_header_ptr -> nx_ip_header_destination_ip <= NX_IP_LOOPBACK_LAST)))
1295 {
1296
1297 /* Let IP packet receive process this packet. */
1298 return (NX_FALSE);
1299 }
1300
1301 /* Clear the packet interface. */
1302 interface_ptr = NX_NULL;
1303
1304 /* Find the suitable interface and next hop address according to the destination ip. */
1305 if(_nx_ip_route_find(ip_ptr, ip_header_ptr -> nx_ip_header_destination_ip, &interface_ptr, &next_hop_address) != NX_SUCCESS)
1306 {
1307
1308 /* Let IP packet receive process this packet. */
1309 return (NX_FALSE);
1310 }
1311
1312 /* Check the NAT forward interface. */
1313 if (interface_ptr != &(ip_ptr -> nx_ip_interface[global_interface_index]))
1314 {
1315
1316 /* Let IP packet receive process this packet. */
1317 return (NX_FALSE);
1318 }
1319
1320 /* Check for IP broadcast. */
1321 if(((ip_header_ptr -> nx_ip_header_destination_ip & interface_ptr -> nx_interface_ip_network_mask) ==
1322 interface_ptr -> nx_interface_ip_network) &&
1323 ((ip_header_ptr -> nx_ip_header_destination_ip & ~(interface_ptr -> nx_interface_ip_network_mask)) ==
1324 ~(interface_ptr -> nx_interface_ip_network_mask)))
1325 {
1326
1327 /* Let IP packet receive process this packet. */
1328 return (NX_FALSE);
1329 }
1330
1331 /* Check if NAT need to process this packet. */
1332 if (packet_process == NX_TRUE)
1333 {
1334
1335 /* Set the packet interface as global interface. */
1336 packet_ptr -> nx_packet_address.nx_packet_interface_ptr = interface_ptr;
1337
1338 #ifndef NX_DISABLE_NAT_INFO
1339 /* Update the count. */
1340 nat_server_ptr -> forwarded_packets_received ++;
1341 #endif
1342
1343 /* Deliver the packet to the outbound packet handler. */
1344 _nx_nat_process_outbound_packet(nat_server_ptr, packet_ptr);
1345 }
1346 }
1347
1348 /* Return NX_TRUE to indicate packet has been processed by NAT. */
1349 return (NX_TRUE);
1350 }
1351
1352
1353 /**************************************************************************/
1354 /* */
1355 /* FUNCTION RELEASE */
1356 /* */
1357 /* _nx_nat_process_inbound_packet PORTABLE C */
1358 /* 6.1 */
1359 /* AUTHOR */
1360 /* */
1361 /* Yuxin Zhou, Microsoft Corporation */
1362 /* */
1363 /* DESCRIPTION */
1364 /* */
1365 /* This function processes a packet from the external network for */
1366 /* forwarding to the private network. It sends each packet to a */
1367 /* protocol handler for protocol specific processing. */
1368 /* */
1369 /* INPUT */
1370 /* */
1371 /* nat_ptr Pointer to the NAT server */
1372 /* packet_ptr Pointer to the packet to process */
1373 /* */
1374 /* OUTPUT */
1375 /* */
1376 /* status Actual completion status */
1377 /* NX_SUCCESS Successful completion status */
1378 /* NX_NAT_INVALID_PROTOCOL Unknown packet protocol */
1379 /* */
1380 /* CALLS */
1381 /* */
1382 /* _nx_nat_process_inbound_TCP_packet */
1383 /* Process external host's TCP packet */
1384 /* _nx_nat_process_inbound_UDCP_packet */
1385 /* Process external host's UDP packet */
1386 /* _nx_nat_process_inbound_ICMP_packet */
1387 /* Process external host's ICMP packet */
1388 /* nx_packet_release Release the packet */
1389 /* */
1390 /* CALLED BY */
1391 /* */
1392 /* _nx_nat_process_packet Process packet from external host */
1393 /* */
1394 /* RELEASE HISTORY */
1395 /* */
1396 /* DATE NAME DESCRIPTION */
1397 /* */
1398 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1399 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1400 /* resulting in version 6.1 */
1401 /* */
1402 /**************************************************************************/
_nx_nat_process_inbound_packet(NX_NAT_DEVICE * nat_ptr,NX_PACKET * packet_ptr)1403 static UINT _nx_nat_process_inbound_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr)
1404 {
1405
1406
1407 UINT status = NX_SUCCESS;
1408 UCHAR protocol;
1409 NX_IPV4_HEADER *ip_header_ptr;
1410 NX_NAT_TRANSLATION_ENTRY translation_entry;
1411
1412
1413 /* Pick a pointer to the IP header. */
1414 ip_header_ptr = (NX_IPV4_HEADER *) packet_ptr -> nx_packet_prepend_ptr;
1415
1416 /* Determine what protocol the current IP datagram is. */
1417 protocol = (ip_header_ptr -> nx_ip_header_word_2 >> 16) & 0xFF;
1418
1419 /* Set up the search criteria in the NAT translation table. */
1420 memset(&translation_entry, 0, sizeof(NX_NAT_TRANSLATION_ENTRY));
1421 translation_entry.peer_ip_address = ip_header_ptr -> nx_ip_header_source_ip;
1422 translation_entry.protocol = protocol;
1423
1424 /* Choose which packet handler by protocol. */
1425 switch (protocol)
1426 {
1427
1428 case NX_PROTOCOL_TCP:
1429 status = _nx_nat_process_inbound_TCP_packet(nat_ptr, packet_ptr, &translation_entry);
1430 break;
1431
1432 case NX_PROTOCOL_UDP:
1433 status = _nx_nat_process_inbound_UDP_packet(nat_ptr, packet_ptr, &translation_entry);
1434 break;
1435
1436 case NX_PROTOCOL_ICMP:
1437 status = _nx_nat_process_inbound_ICMP_packet(nat_ptr, packet_ptr, &translation_entry);
1438 break;
1439 }
1440
1441 /* Return completion status. */
1442 return status;
1443 }
1444
1445
1446 /**************************************************************************/
1447 /* */
1448 /* FUNCTION RELEASE */
1449 /* */
1450 /* _nx_nat_process_inbound_TCP_packet PORTABLE C */
1451 /* 6.1 */
1452 /* AUTHOR */
1453 /* */
1454 /* Yuxin Zhou, Microsoft Corporation */
1455 /* */
1456 /* DESCRIPTION */
1457 /* */
1458 /* This function finds the local IP address:port for an incoming packet */
1459 /* in the NAT translation table and replaces the global packet */
1460 /* destination IP address and port with the local IP address and port. */
1461 /* If none is found, it rejects the packet. Otherwise it updates the TCP*/
1462 /* checksum with the changed IP address and port. The packet is then */
1463 /* sent to private host. */
1464 /* */
1465 /* INPUT */
1466 /* */
1467 /* nat_ptr Pointer to the NAT server */
1468 /* packet_ptr Pointer to the packet to process */
1469 /* entry_ptr Pointer to the entry */
1470 /* */
1471 /* OUTPUT */
1472 /* */
1473 /* status Actual completion status */
1474 /* NX_SUCCESS Successful completion status */
1475 /* (packet is not necessarily */
1476 /* forwarded) */
1477 /* */
1478 /* CALLS */
1479 /* */
1480 /* _nx_nat_inbound_entry_find Find inbound entry in entry list */
1481 /* _nx_nat_ip_packet_send Send packet to private interface */
1482 /* nx_packet_release Release the packet */
1483 /* */
1484 /* CALLED BY */
1485 /* */
1486 /* _nx_nat_process_inbound_packet Process inbound packets */
1487 /* */
1488 /* RELEASE HISTORY */
1489 /* */
1490 /* DATE NAME DESCRIPTION */
1491 /* */
1492 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1493 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1494 /* resulting in version 6.1 */
1495 /* */
1496 /**************************************************************************/
_nx_nat_process_inbound_TCP_packet(NX_NAT_DEVICE * nat_ptr,NX_PACKET * packet_ptr,NX_NAT_TRANSLATION_ENTRY * entry_ptr)1497 static UINT _nx_nat_process_inbound_TCP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr)
1498 {
1499
1500 UINT status;
1501 UINT entry_found;
1502 USHORT old_port;
1503 USHORT new_port;
1504 ULONG old_address;
1505 ULONG new_address;
1506 USHORT checksum;
1507 ULONG compute_checksum;
1508 ULONG next_hop_address;
1509 NX_TCP_HEADER *tcp_header_ptr;
1510 NX_NAT_TRANSLATION_ENTRY *record_entry;
1511
1512
1513 /* Initialize local variables. */
1514 compute_checksum = 1;
1515 record_entry = NX_NULL;
1516 entry_found = NX_TRUE;
1517
1518 /* Pickup the pointer to the head of the TCP packet. */
1519 packet_ptr -> nx_packet_prepend_ptr += sizeof(NX_IPV4_HEADER);
1520 packet_ptr -> nx_packet_length -= sizeof(NX_IPV4_HEADER);
1521 tcp_header_ptr = (NX_TCP_HEADER *) (packet_ptr -> nx_packet_prepend_ptr);
1522
1523 /* For little endian processors, adjust byte order for big endianness. */
1524 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_0);
1525 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_sequence_number);
1526 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_acknowledgment_number);
1527 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_3);
1528 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_4);
1529
1530 /* Find the inbound entry, set the packet private interface and next hop address. */
1531 status = _nx_nat_inbound_entry_find(nat_ptr, packet_ptr, entry_ptr, &record_entry, &next_hop_address);
1532
1533 /* Check for error. */
1534 if (status != NX_SUCCESS)
1535 {
1536
1537 #ifndef NX_DISABLE_NAT_INFO
1538 /* Update the count. */
1539 nat_ptr -> forwarded_packets_dropped++;
1540 #endif
1541
1542 /* Check the status. */
1543 if (status == NX_NAT_ENTRY_NOT_FOUND)
1544 {
1545
1546 /* Set the entry found flag. */
1547 entry_found = NX_FALSE;
1548 }
1549 else
1550 {
1551
1552 /* Release the packet */
1553 nx_packet_release(packet_ptr);
1554
1555 /* Return completion status. */
1556 return NX_SUCCESS;
1557 }
1558 }
1559 else
1560 {
1561
1562 /* Check the inbound packet destination port, and update the TCP header. */
1563 if (record_entry -> external_port != record_entry -> local_port)
1564 {
1565
1566 /* Replace the destination port with the local (source) port of the preceding outbound packet. */
1567
1568 tcp_header_ptr -> nx_tcp_header_word_0 = ((ULONG)(tcp_header_ptr -> nx_tcp_header_word_0 & ~NX_LOWER_16_MASK)) |
1569 ((ULONG) record_entry -> local_port);
1570 }
1571
1572 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
1573 if(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_TCP_TX_CHECKSUM)
1574 compute_checksum = 0;
1575 else
1576 compute_checksum = 1;
1577 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
1578 if(compute_checksum)
1579 {
1580
1581 /* Get the old checksum. */
1582 checksum = (USHORT)(tcp_header_ptr -> nx_tcp_header_word_4 >> NX_SHIFT_BY_16);
1583
1584 /* Check whether the port is updated. */
1585 if (record_entry -> external_port != record_entry -> local_port)
1586 {
1587
1588 /* Set the old port and new port. */
1589 old_port = record_entry -> external_port;
1590 new_port = record_entry -> local_port;
1591
1592 /* Adjust the checksum for port. */
1593 _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_port, sizeof(USHORT), (UCHAR *)&new_port, sizeof(USHORT));
1594 }
1595
1596 /* Set the old address and new address. */
1597 old_address = nat_ptr -> nx_nat_ip_ptr -> nx_ip_interface[nat_ptr -> nx_nat_global_interface_index].nx_interface_ip_address;
1598 new_address = record_entry -> local_ip_address;
1599
1600 /* Adjust the checksum for address. */
1601 _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_address, sizeof(LONG), (UCHAR *)&new_address, sizeof(LONG));
1602
1603 /* OK to clear the TCP checksum field to zero before the checksum update. */
1604 tcp_header_ptr -> nx_tcp_header_word_4 = tcp_header_ptr -> nx_tcp_header_word_4 & NX_LOWER_16_MASK;
1605
1606 /* Place the checksum into the first header word. */
1607 tcp_header_ptr -> nx_tcp_header_word_4 = tcp_header_ptr -> nx_tcp_header_word_4 | (ULONG)(checksum << NX_SHIFT_BY_16);
1608 }
1609 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
1610 else
1611 {
1612
1613 /* OK to clear the TCP checksum field to zero before the checksum update. */
1614 tcp_header_ptr -> nx_tcp_header_word_4 = tcp_header_ptr -> nx_tcp_header_word_4 & NX_LOWER_16_MASK;
1615
1616 /* Set the flag. */
1617 packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_TCP_TX_CHECKSUM;
1618 }
1619 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
1620 }
1621
1622 /* Swap endianness back before sending. */
1623 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_sequence_number);
1624 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_acknowledgment_number);
1625 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_0);
1626 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_3);
1627 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_4);
1628
1629 /* Check the entry found flag. */
1630 if (entry_found == NX_FALSE)
1631 {
1632
1633 /* Stop processing, recover packet length to Let NetXDuo process this packet. */
1634 packet_ptr -> nx_packet_prepend_ptr -= sizeof(NX_IPV4_HEADER);
1635 packet_ptr -> nx_packet_length += sizeof(NX_IPV4_HEADER);
1636
1637 /* Let NetXDuo process this pcaket. */
1638 return(NX_NAT_PACKET_CONSUMED_FAILED);
1639 }
1640
1641 /* Send the TCP packet onto the private host. */
1642 _nx_nat_ip_packet_send(nat_ptr, packet_ptr, record_entry, NX_NAT_INBOUND_PACKET, next_hop_address);
1643
1644 /* Return completion status. */
1645 return NX_SUCCESS;
1646 }
1647
1648
1649 /**************************************************************************/
1650 /* */
1651 /* FUNCTION RELEASE */
1652 /* */
1653 /* _nx_nat_process_inbound_UDP_packet PORTABLE C */
1654 /* 6.1 */
1655 /* AUTHOR */
1656 /* */
1657 /* Yuxin Zhou, Microsoft Corporation */
1658 /* */
1659 /* DESCRIPTION */
1660 /* */
1661 /* This function finds the local IP address:port for an incoming packet */
1662 /* in the NAT translation table and replaces the global packet */
1663 /* destination IP address and port with the local IP address andport. */
1664 /* If none is found, it rejects the packet. Otherwise it updates the UDP*/
1665 /* checksum with the changed IP address and port. The packet is then */
1666 /* sent to private host. */
1667 /* */
1668 /* INPUT */
1669 /* */
1670 /* nat_ptr Pointer to the NAT server */
1671 /* packet_ptr Pointer to the packet to process */
1672 /* entry_ptr Pointer to the entry */
1673 /* */
1674 /* OUTPUT */
1675 /* */
1676 /* status Actual completion status */
1677 /* NX_SUCCESS Successful completion status */
1678 /* NX_NAT_INVALID_IP_HEADER Invalid IP header */
1679 /* NX_NAT_BAD_UDP_CHECKSUM UDP checksum is invalid */
1680 /* */
1681 /* CALLS */
1682 /* */
1683 /* _nx_nat_inbound_entry_find Find inbound entry in entry list */
1684 /* _nx_nat_ip_packet_send Send packet to private interface */
1685 /* nx_packet_release Release the packet */
1686 /* */
1687 /* CALLED BY */
1688 /* */
1689 /* _nx_nat_process_inbound_packet Process inbound packets */
1690 /* */
1691 /* RELEASE HISTORY */
1692 /* */
1693 /* DATE NAME DESCRIPTION */
1694 /* */
1695 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1696 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1697 /* resulting in version 6.1 */
1698 /* */
1699 /**************************************************************************/
_nx_nat_process_inbound_UDP_packet(NX_NAT_DEVICE * nat_ptr,NX_PACKET * packet_ptr,NX_NAT_TRANSLATION_ENTRY * entry_ptr)1700 static UINT _nx_nat_process_inbound_UDP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr)
1701 {
1702
1703 UINT status;
1704 UINT entry_found;
1705 USHORT old_port;
1706 USHORT new_port;
1707 ULONG old_address;
1708 ULONG new_address;
1709 USHORT checksum;
1710 ULONG compute_checksum;
1711 ULONG next_hop_address;
1712 NX_UDP_HEADER *udp_header_ptr;
1713 NX_NAT_TRANSLATION_ENTRY *record_entry;
1714
1715
1716 /* Initialize local variables. */
1717 compute_checksum = 1;
1718 record_entry = NX_NULL;
1719 entry_found = NX_TRUE;
1720
1721 /* Pickup the pointer to the head of the UDP packet. */
1722 packet_ptr -> nx_packet_prepend_ptr += sizeof(NX_IPV4_HEADER);
1723 packet_ptr -> nx_packet_length -= sizeof(NX_IPV4_HEADER);
1724 udp_header_ptr = (NX_UDP_HEADER *) (packet_ptr -> nx_packet_prepend_ptr);
1725
1726 /* For little endian processors, adjust byte order for big endianness. */
1727 NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_0);
1728 NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1);
1729
1730 /* Find the inbound entry, set the packet private interface and next hop address. */
1731 status = _nx_nat_inbound_entry_find(nat_ptr, packet_ptr, entry_ptr, &record_entry, &next_hop_address);
1732
1733 /* Check for error. */
1734 if (status != NX_SUCCESS)
1735 {
1736
1737 #ifndef NX_DISABLE_NAT_INFO
1738 /* Update the count. */
1739 nat_ptr -> forwarded_packets_dropped++;
1740 #endif
1741
1742 /* Check the status. */
1743 if (status == NX_NAT_ENTRY_NOT_FOUND)
1744 {
1745
1746 /* Set the entry found flag. */
1747 entry_found = NX_FALSE;
1748 }
1749 else
1750 {
1751
1752 /* Release the packet */
1753 nx_packet_release(packet_ptr);
1754
1755 /* Return completion status. */
1756 return NX_SUCCESS;
1757 }
1758 }
1759 else
1760 {
1761
1762 /* Update the destination port if the NAT device mapped it to another port. */
1763 if (record_entry -> external_port != record_entry -> local_port)
1764 {
1765
1766 /* Translate the destination UDP port to the private host port. If translation
1767 does not involve port number this will essentially be the original port number. */
1768 udp_header_ptr -> nx_udp_header_word_0 = ((ULONG) (udp_header_ptr -> nx_udp_header_word_0 & ~NX_LOWER_16_MASK)) |
1769 ((ULONG) record_entry -> local_port);
1770 }
1771
1772 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
1773 if(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_UDP_TX_CHECKSUM)
1774 compute_checksum = 0;
1775 else
1776 compute_checksum = 1;
1777 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
1778
1779 /* Get the checksum. */
1780 checksum = udp_header_ptr -> nx_udp_header_word_1 & NX_LOWER_16_MASK;
1781
1782 /* UDP headers with 0 checksum should not be modified, RFC3022, Section4.1, Page8. */
1783 if (checksum == 0)
1784 compute_checksum = 0;
1785
1786 /* Check the checksum. */
1787 if(compute_checksum)
1788 {
1789
1790 /* Check whether the port is updated. */
1791 if (record_entry -> external_port != record_entry -> local_port)
1792 {
1793
1794 /* Set the old port and new port. */
1795 old_port = record_entry -> external_port;
1796 new_port = record_entry -> local_port;
1797
1798 /* Adjust the checksum for port. */
1799 _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_port, sizeof(USHORT), (UCHAR *)&new_port, sizeof(USHORT));
1800 }
1801
1802 /* Set the old address and new address. */
1803 old_address = nat_ptr -> nx_nat_ip_ptr -> nx_ip_interface[nat_ptr -> nx_nat_global_interface_index].nx_interface_ip_address;
1804 new_address = record_entry -> local_ip_address;
1805
1806 /* Adjust the checksum for address. */
1807 _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_address, sizeof(LONG), (UCHAR *)&new_address, sizeof(LONG));
1808
1809 /* OK to clear the UDP checksum field to zero before the checksum update. */
1810 udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 & ~NX_LOWER_16_MASK;
1811
1812 /* Place the checksum into the first header word. */
1813 udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 | checksum;
1814 }
1815 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
1816 else
1817 {
1818
1819 /* OK to clear the UDP checksum field to zero before the checksum update. */
1820 udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 & ~NX_LOWER_16_MASK;
1821
1822 /* Set the flag. */
1823 packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_UDP_TX_CHECKSUM;
1824 }
1825 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
1826 }
1827
1828 /* Swap UDP header byte order back to big endian before sending. For big endian processors,
1829 this will have no effect. */
1830 NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_0);
1831 NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1);
1832
1833 /* Check the packet consumed flag. */
1834 if (entry_found == NX_FALSE)
1835 {
1836
1837 /* Stop processing, recover packet length to Let NetXDuo process this packet. */
1838 packet_ptr -> nx_packet_prepend_ptr -= sizeof(NX_IPV4_HEADER);
1839 packet_ptr -> nx_packet_length += sizeof(NX_IPV4_HEADER);
1840
1841 /* Let NetXDuo process this pcaket. */
1842 return(NX_NAT_PACKET_CONSUMED_FAILED);
1843 }
1844
1845 /* Send the UDP packet onto the private host. */
1846 _nx_nat_ip_packet_send(nat_ptr, packet_ptr, record_entry, NX_NAT_INBOUND_PACKET, next_hop_address);
1847
1848 /* Return completion status. */
1849 return NX_SUCCESS;
1850 }
1851
1852
1853 /**************************************************************************/
1854 /* */
1855 /* FUNCTION RELEASE */
1856 /* */
1857 /* _nx_nat_process_inbound_ICMP_packet PORTABLE C */
1858 /* 6.1 */
1859 /* AUTHOR */
1860 /* */
1861 /* Yuxin Zhou, Microsoft Corporation */
1862 /* */
1863 /* DESCRIPTION */
1864 /* */
1865 /* This function finds the local IP address:port for an incoming packet */
1866 /* in the NAT translation table and replaces the global packet */
1867 /* IP address and queryID with the local IP address and queryID. */
1868 /* If none is found, rejects the packet. Otherwise it updates the ICMP */
1869 /* checksum with the changed IP address and port. The packet is then */
1870 /* sent to private host. */
1871 /* */
1872 /* INPUT */
1873 /* */
1874 /* nat_ptr Pointer to the NAT server */
1875 /* packet_ptr Pointer to the packet to process */
1876 /* entry_ptr Pointer to the entry */
1877 /* */
1878 /* OUTPUT */
1879 /* */
1880 /* status Actual completion status */
1881 /* NX_SUCCESS Successful completion status */
1882 /* (packet is not necessarily */
1883 /* forwarded) */
1884 /* */
1885 /* CALLS */
1886 /* */
1887 /* _nx_nat_inbound_entry_find Find inbound entry in entry list */
1888 /* _nx_nat_ip_packet_send Send packet to private interface */
1889 /* nx_packet_release Release the packet */
1890 /* */
1891 /* CALLED BY */
1892 /* */
1893 /* _nx_nat_process_inbound_packet Process inbound packets */
1894 /* */
1895 /* RELEASE HISTORY */
1896 /* */
1897 /* DATE NAME DESCRIPTION */
1898 /* */
1899 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
1900 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
1901 /* resulting in version 6.1 */
1902 /* */
1903 /**************************************************************************/
_nx_nat_process_inbound_ICMP_packet(NX_NAT_DEVICE * nat_ptr,NX_PACKET * packet_ptr,NX_NAT_TRANSLATION_ENTRY * entry_ptr)1904 static UINT _nx_nat_process_inbound_ICMP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr)
1905 {
1906 UINT status;
1907 UINT entry_found;
1908 ULONG sequence;
1909 UINT type;
1910 USHORT old_port;
1911 USHORT new_port;
1912 USHORT checksum;
1913 ULONG compute_checksum;
1914 ULONG next_hop_address;
1915 NX_ICMP_HEADER *icmp_header_ptr;
1916 NX_NAT_TRANSLATION_ENTRY *record_entry;
1917
1918
1919 /* Initialize local variables. */
1920 compute_checksum = 1;
1921 record_entry = NX_NULL;
1922 entry_found = NX_TRUE;
1923
1924 /* Get a pointer to the ICMP header. */
1925 packet_ptr -> nx_packet_prepend_ptr += sizeof(NX_IPV4_HEADER);
1926 packet_ptr -> nx_packet_length -= sizeof(NX_IPV4_HEADER);
1927 icmp_header_ptr = (NX_ICMP_HEADER *)(packet_ptr -> nx_packet_prepend_ptr);
1928
1929 /* Adjust ICMP header byte order for endianness. */
1930 NX_CHANGE_ULONG_ENDIAN(icmp_header_ptr -> nx_icmp_header_word_0);
1931 NX_CHANGE_ULONG_ENDIAN(icmp_header_ptr -> nx_icmp_header_word_1);
1932
1933 /* Extract the ICMP type and code. */
1934 type = icmp_header_ptr -> nx_icmp_header_word_0 >> 24;
1935
1936 /* Find the inbound entry, set the packet private interface and next hop address. */
1937 status = _nx_nat_inbound_entry_find(nat_ptr, packet_ptr, entry_ptr, &record_entry, &next_hop_address);
1938
1939 /* Check for error. */
1940 if (status != NX_SUCCESS)
1941 {
1942
1943 #ifndef NX_DISABLE_NAT_INFO
1944 /* Update the count. */
1945 nat_ptr -> forwarded_packets_dropped++;
1946 #endif
1947
1948 /* Check the status. */
1949 if (status == NX_NAT_ENTRY_NOT_FOUND)
1950 {
1951
1952 /* Set the entry found flag. */
1953 entry_found = NX_FALSE;
1954 }
1955 else
1956 {
1957
1958 /* Release the packet */
1959 nx_packet_release(packet_ptr);
1960
1961 /* Return completion status. */
1962 return NX_SUCCESS;
1963 }
1964 }
1965 else
1966 {
1967
1968 /* Check the type. */
1969 if ((type != NX_ICMP_ECHO_REPLY_TYPE) &&
1970 (type != NX_ICMP_ECHO_REQUEST_TYPE))
1971 {
1972
1973 #ifndef NX_DISABLE_NAT_INFO
1974 /* Unknown ICMP packet. Drop the packet and bail! */
1975 nat_ptr -> forwarded_packets_dropped++;
1976 #endif
1977
1978 nx_packet_release(packet_ptr);
1979
1980 return NX_SUCCESS;
1981 }
1982
1983 /* Now we have to translate the packet destination for private host address and
1984 update packet header checksum. */
1985 if ((type == NX_ICMP_ECHO_REPLY_TYPE) && (record_entry -> external_port != record_entry -> local_port))
1986 {
1987
1988 /* Restore the local host ICMP Query ID. */
1989 sequence = icmp_header_ptr -> nx_icmp_header_word_1 & NX_LOWER_16_MASK;
1990
1991 /* Restore the local host ICMP Query ID from the 'source port' field in the NAT table entry. */
1992 icmp_header_ptr -> nx_icmp_header_word_1 = (ULONG)(record_entry -> local_port << NX_SHIFT_BY_16) | sequence;
1993
1994 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
1995 if(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_ICMPV4_TX_CHECKSUM)
1996 compute_checksum = 0;
1997 else
1998 compute_checksum = 1;
1999 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
2000 if(compute_checksum)
2001 {
2002
2003 /* Set the old checksum. */
2004 checksum = icmp_header_ptr -> nx_icmp_header_word_0 & NX_LOWER_16_MASK;
2005
2006 /* Set the old port and new port. */
2007 old_port = entry_ptr -> external_port;
2008 new_port = record_entry -> local_port;
2009
2010 /* Adjust the checksum. */
2011 _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_port, sizeof(USHORT), (UCHAR *)&new_port, sizeof(USHORT));
2012
2013 /* Ok to zero out the checksum because we'll replace it with an updated checksum. */
2014 icmp_header_ptr -> nx_icmp_header_word_0 = icmp_header_ptr -> nx_icmp_header_word_0 & ~NX_LOWER_16_MASK;
2015
2016 /* Place the checksum into the first header word. */
2017 icmp_header_ptr -> nx_icmp_header_word_0 = icmp_header_ptr -> nx_icmp_header_word_0 | checksum;
2018 }
2019 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
2020 else
2021 {
2022
2023 /* Set the checksum to zero. */
2024 icmp_header_ptr -> nx_icmp_header_word_0 = icmp_header_ptr -> nx_icmp_header_word_0 & ~NX_LOWER_16_MASK;
2025
2026 /* Set the flag. */
2027 packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_ICMPV4_TX_CHECKSUM;
2028 }
2029 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
2030 }
2031 }
2032
2033 /* If NX_LITTLE_ENDIAN is defined, the headers need to be swapped to match
2034 that of the data area. */
2035 NX_CHANGE_ULONG_ENDIAN(icmp_header_ptr -> nx_icmp_header_word_0);
2036 NX_CHANGE_ULONG_ENDIAN(icmp_header_ptr -> nx_icmp_header_word_1);
2037
2038 /* Check the packet consumed flag. */
2039 if (entry_found == NX_FALSE)
2040 {
2041
2042 /* Stop processing, recover packet length to Let NetXDuo process this packet. */
2043 packet_ptr -> nx_packet_prepend_ptr -= sizeof(NX_IPV4_HEADER);
2044 packet_ptr -> nx_packet_length += sizeof(NX_IPV4_HEADER);
2045
2046 /* Let NetXDuo process this pcaket. */
2047 return(NX_NAT_PACKET_CONSUMED_FAILED);
2048 }
2049
2050 /* Send the ICMP packet onto the private host. */
2051 _nx_nat_ip_packet_send(nat_ptr, packet_ptr, record_entry, NX_NAT_INBOUND_PACKET, next_hop_address);
2052
2053 /* Return packet send completion status. */
2054 return NX_SUCCESS;
2055 }
2056
2057
2058 /**************************************************************************/
2059 /* */
2060 /* FUNCTION RELEASE */
2061 /* */
2062 /* _nx_nat_process_outbound_packet PORTABLE C */
2063 /* 6.1 */
2064 /* AUTHOR */
2065 /* */
2066 /* Yuxin Zhou, Microsoft Corporation */
2067 /* */
2068 /* DESCRIPTION */
2069 /* */
2070 /* This function processes a packet from a local host bound for the */
2071 /* external network. If a matching entry for the private host is not */
2072 /* found in the NAT translation table, one is created. Packets are then*/
2073 /* directed to protocol specific handlers for detailed processing of the*/
2074 /* packet before sending out on the external network. */
2075 /* */
2076 /* INPUT */
2077 /* */
2078 /* nat_ptr Pointer to the NAT server */
2079 /* packet_ptr Pointer to the packet to process */
2080 /* */
2081 /* OUTPUT */
2082 /* */
2083 /* status Actual completion status */
2084 /* NX_SUCCESS Successful completion status */
2085 /* NX_NAT_INVALID_PROTOCOL Unknown/unsupported protocol status*/
2086 /* */
2087 /* CALLS */
2088 /* */
2089 /* _nx_nat_process_outbound_TCP_packet */
2090 /* Handler for outbound TCP packets */
2091 /* _nx_nat_process_outbound_UDP_packet */
2092 /* Handler for outbound UDP packets */
2093 /* _nx_nat_process_outbound_ICMP_packet */
2094 /* Handler for outbound ICMP packets */
2095 /* nx_packet_release Release packet back to packet pool */
2096 /* */
2097 /* CALLED BY */
2098 /* */
2099 /* _nx_nat_packet_process Process packets forwarded to NAT by*/
2100 /* Netx */
2101 /* */
2102 /* RELEASE HISTORY */
2103 /* */
2104 /* DATE NAME DESCRIPTION */
2105 /* */
2106 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2107 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2108 /* resulting in version 6.1 */
2109 /* */
2110 /**************************************************************************/
_nx_nat_process_outbound_packet(NX_NAT_DEVICE * nat_ptr,NX_PACKET * packet_ptr)2111 static UINT _nx_nat_process_outbound_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr)
2112 {
2113
2114 UCHAR protocol;
2115 NX_IPV4_HEADER *ip_header_ptr;
2116 NX_NAT_TRANSLATION_ENTRY translation_entry;
2117
2118
2119 /* Set up an actual IP header pointer. */
2120 ip_header_ptr = (NX_IPV4_HEADER *) (packet_ptr -> nx_packet_prepend_ptr);
2121
2122 /* Determine what protocol the current IP datagram is. */
2123 protocol = (ip_header_ptr -> nx_ip_header_word_2 >> 16) & 0xFF;
2124
2125 /* Set up the search criteria in the NAT translation table. */
2126 memset(&translation_entry, 0, sizeof(NX_NAT_TRANSLATION_ENTRY));
2127 translation_entry.local_ip_address = ip_header_ptr -> nx_ip_header_source_ip;
2128 translation_entry.peer_ip_address = ip_header_ptr -> nx_ip_header_destination_ip;
2129 translation_entry.protocol = protocol;
2130
2131 /* Direct the packet to a protocol specific handler. */
2132 switch (protocol)
2133 {
2134
2135 case NX_PROTOCOL_TCP:
2136 /* Process the packet for TCP protocol. */
2137 _nx_nat_process_outbound_TCP_packet(nat_ptr, packet_ptr, &translation_entry);
2138 break;
2139
2140 case NX_PROTOCOL_UDP:
2141 /* Process the packet for UDP protocol. */
2142 _nx_nat_process_outbound_UDP_packet(nat_ptr, packet_ptr, &translation_entry);
2143 break;
2144
2145 case NX_PROTOCOL_ICMP:
2146 /* Process the packet for ICMP (including error message packets) protocol. */
2147 _nx_nat_process_outbound_ICMP_packet(nat_ptr, packet_ptr, &translation_entry);
2148 break;
2149
2150 default:
2151 {
2152
2153 #ifndef NX_DISABLE_NAT_INFO
2154 /* Update the count. */
2155 nat_ptr -> forwarded_packets_dropped++;
2156 #endif
2157
2158 /* Toss the IP packet since we don't know what to do with it! */
2159 nx_packet_release(packet_ptr);
2160
2161 return NX_NAT_INVALID_PROTOCOL;
2162 }
2163 }
2164
2165 /* Return completion status. */
2166 return NX_SUCCESS;
2167 }
2168
2169
2170 /**************************************************************************/
2171 /* */
2172 /* FUNCTION RELEASE */
2173 /* */
2174 /* _nx_nat_process_outbound_TCP_packet PORTABLE C */
2175 /* 6.1 */
2176 /* AUTHOR */
2177 /* */
2178 /* Yuxin Zhou, Microsoft Corporation */
2179 /* */
2180 /* DESCRIPTION */
2181 /* */
2182 /* This function processes a TCP packet from a local host on the private*/
2183 /* network destined for the external network with a global IP address */
2184 /* and port. The source IP address and port are replaced by NAT with a */
2185 /* global IP address:port. NAT then updates the TCP header checksum. */
2186 /* */
2187 /* INPUT */
2188 /* */
2189 /* nat_ptr Pointer to the NAT server */
2190 /* packet_ptr Pointer to the packet to process */
2191 /* entry_ptr Pointer to the entry */
2192 /* */
2193 /* OUTPUT */
2194 /* */
2195 /* status Actual completion status */
2196 /* NX_SUCCESS Successful completion status */
2197 /* */
2198 /* CALLS */
2199 /* */
2200 /* _nx_nat_outbound_entry_find Find outbound entry in entry list */
2201 /* _nx_nat_ip_packet_send Send packet to private interface */
2202 /* nx_packet_release Release the packet */
2203 /* */
2204 /* CALLED BY */
2205 /* */
2206 /* Application code */
2207 /* */
2208 /* RELEASE HISTORY */
2209 /* */
2210 /* DATE NAME DESCRIPTION */
2211 /* */
2212 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2213 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2214 /* resulting in version 6.1 */
2215 /* */
2216 /**************************************************************************/
_nx_nat_process_outbound_TCP_packet(NX_NAT_DEVICE * nat_ptr,NX_PACKET * packet_ptr,NX_NAT_TRANSLATION_ENTRY * entry_ptr)2217 static UINT _nx_nat_process_outbound_TCP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr)
2218 {
2219
2220 UINT status;
2221 USHORT old_port;
2222 USHORT new_port;
2223 ULONG old_address;
2224 ULONG new_address;
2225 USHORT checksum;
2226 ULONG compute_checksum;
2227 ULONG next_hop_address;
2228 NX_TCP_HEADER *tcp_header_ptr;
2229 NX_NAT_TRANSLATION_ENTRY *record_entry;
2230
2231
2232 /* Initialize local variables. */
2233 compute_checksum = 1;
2234
2235 /* Pickup the pointer to the head of the UDP packet. */
2236 packet_ptr -> nx_packet_prepend_ptr += sizeof(NX_IPV4_HEADER);
2237 packet_ptr -> nx_packet_length -= sizeof(NX_IPV4_HEADER);
2238 tcp_header_ptr = (NX_TCP_HEADER *) (packet_ptr -> nx_packet_prepend_ptr);
2239
2240 /* Adjust byte order for endianness. */
2241 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_0);
2242 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_sequence_number);
2243 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_acknowledgment_number);
2244 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_3);
2245 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_4);
2246
2247 /* Find the outbound entry, set the packet global interface and next hop address. */
2248 status = _nx_nat_outbound_entry_find(nat_ptr, packet_ptr, entry_ptr, &record_entry, &next_hop_address);
2249
2250 /* Check for error. */
2251 if (status != NX_SUCCESS)
2252 {
2253
2254 #ifndef NX_DISABLE_NAT_INFO
2255 /* Increase the session count of dropped forwarded packets. */
2256 nat_ptr -> forwarded_packets_dropped++;
2257 #endif
2258
2259 /* Release the packet back to the packet pool. */
2260 nx_packet_release(packet_ptr);
2261
2262 /* Return the error status. */
2263 return status;
2264 }
2265
2266 /* Update the source port if the NAT device mapped it to another port. */
2267 if (record_entry -> external_port != record_entry -> local_port)
2268 {
2269
2270 /* Yes, write to the upper bits of the TCP word. */
2271 tcp_header_ptr -> nx_tcp_header_word_0 = (tcp_header_ptr -> nx_tcp_header_word_0 & NX_LOWER_16_MASK) |
2272 (((ULONG) (record_entry -> external_port)) << NX_SHIFT_BY_16);
2273 }
2274
2275 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
2276 if(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_TCP_TX_CHECKSUM)
2277 compute_checksum = 0;
2278 else
2279 compute_checksum = 1;
2280 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
2281 if(compute_checksum)
2282 {
2283
2284 /* Get the old checksum. */
2285 checksum = (USHORT)(tcp_header_ptr -> nx_tcp_header_word_4 >> NX_SHIFT_BY_16);
2286
2287 /* Check whether the port is updated. */
2288 if (record_entry -> external_port != record_entry -> local_port)
2289 {
2290
2291 /* Set the old port and new port. */
2292 old_port = record_entry -> local_port;
2293 new_port = record_entry -> external_port;
2294
2295 /* Adjust the checksum for port. */
2296 _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_port, sizeof(USHORT), (UCHAR *)&new_port, sizeof(USHORT));
2297 }
2298
2299 /* Set the old address and new address. */
2300 old_address = record_entry -> local_ip_address;
2301 new_address = nat_ptr -> nx_nat_ip_ptr -> nx_ip_interface[nat_ptr -> nx_nat_global_interface_index].nx_interface_ip_address;
2302
2303 /* Adjust the checksum for address. */
2304 _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_address, sizeof(LONG), (UCHAR *)&new_address, sizeof(LONG));
2305
2306 /* OK to clear the TCP checksum field to zero before the checksum update. */
2307 tcp_header_ptr -> nx_tcp_header_word_4 = tcp_header_ptr -> nx_tcp_header_word_4 & NX_LOWER_16_MASK;
2308
2309 /* Place the checksum into the first header word. */
2310 tcp_header_ptr -> nx_tcp_header_word_4 = tcp_header_ptr -> nx_tcp_header_word_4 | (ULONG)(checksum << NX_SHIFT_BY_16);
2311 }
2312 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
2313 else
2314 {
2315
2316 /* OK to clear the TCP checksum field to zero before the checksum update. */
2317 tcp_header_ptr -> nx_tcp_header_word_4 = tcp_header_ptr -> nx_tcp_header_word_4 & NX_LOWER_16_MASK;
2318
2319 /* Set the flag. */
2320 packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_TCP_TX_CHECKSUM;
2321 }
2322 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
2323
2324 /* Swap byte order back to big endian before sending if little endian is specified. */
2325 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_0);
2326 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_sequence_number);
2327 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_acknowledgment_number);
2328 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_3);
2329 NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_4);
2330
2331 /* Send the TCP packet onto the global host. */
2332 _nx_nat_ip_packet_send(nat_ptr,packet_ptr, record_entry, NX_NAT_OUTBOUND_PACKET, next_hop_address);
2333
2334 return NX_SUCCESS;
2335 }
2336
2337
2338 /**************************************************************************/
2339 /* */
2340 /* FUNCTION RELEASE */
2341 /* */
2342 /* _nx_nat_process_outbound_UDP_packet PORTABLE C */
2343 /* 6.1 */
2344 /* AUTHOR */
2345 /* */
2346 /* Yuxin Zhou, Microsoft Corporation */
2347 /* */
2348 /* DESCRIPTION */
2349 /* */
2350 /* This function processes a UDP packet from a local host destined for */
2351 /* the external network; NAT replaces the private IP address:port with a*/
2352 /* global IP address:port. NAT updates the UDP header checksum field for*/
2353 /* all packets having a non zero UDP packet checksum. */
2354 /* */
2355 /* INPUT */
2356 /* */
2357 /* nat_ptr Pointer to the NAT server */
2358 /* packet_ptr Pointer to the packet to process */
2359 /* entry_ptr Pointer to the entry */
2360 /* */
2361 /* OUTPUT */
2362 /* */
2363 /* status Actual completion status */
2364 /* NX_SUCCESS Successful completion status */
2365 /* NX_NAT_ZERO_UDP_CHECKSUM Illegal zero UDP header checksum */
2366 /* NX_NAT_BAD_UDP_CHECKSUM UDP header checksum is invalid */
2367 /* */
2368 /* CALLS */
2369 /* */
2370 /* _nx_nat_outbound_entry_find Find outbound entry in entry list */
2371 /* _nx_nat_ip_packet_send Send packet to private interface */
2372 /* nx_packet_release Release the packet */
2373 /* */
2374 /* CALLED BY */
2375 /* */
2376 /* Application code */
2377 /* */
2378 /* RELEASE HISTORY */
2379 /* */
2380 /* DATE NAME DESCRIPTION */
2381 /* */
2382 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2383 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2384 /* resulting in version 6.1 */
2385 /* */
2386 /**************************************************************************/
_nx_nat_process_outbound_UDP_packet(NX_NAT_DEVICE * nat_ptr,NX_PACKET * packet_ptr,NX_NAT_TRANSLATION_ENTRY * entry_ptr)2387 static UINT _nx_nat_process_outbound_UDP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr)
2388 {
2389
2390 UINT status;
2391 USHORT old_port;
2392 USHORT new_port;
2393 ULONG old_address;
2394 ULONG new_address;
2395 USHORT checksum;
2396 ULONG compute_checksum;
2397 ULONG next_hop_address;
2398 NX_UDP_HEADER *udp_header_ptr;
2399 NX_NAT_TRANSLATION_ENTRY *record_entry;
2400
2401 /* Initialize local variables. */
2402 compute_checksum = 1;
2403
2404 /* Pickup the pointer to the head of the UDP packet. */
2405 packet_ptr -> nx_packet_prepend_ptr += sizeof(NX_IPV4_HEADER);
2406 packet_ptr -> nx_packet_length -= sizeof(NX_IPV4_HEADER);
2407 udp_header_ptr = (NX_UDP_HEADER *) (packet_ptr -> nx_packet_prepend_ptr);
2408
2409 /* For little endian processors, swap byte order to little endian. */
2410 NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_0);
2411 NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1);
2412
2413 /* Find the outbound entry, set the packet global interface and next hop address. */
2414 status = _nx_nat_outbound_entry_find(nat_ptr, packet_ptr, entry_ptr, &record_entry, &next_hop_address);
2415
2416 /* Check for error. */
2417 if (status != NX_SUCCESS)
2418 {
2419
2420 #ifndef NX_DISABLE_NAT_INFO
2421 /* Increase the session count of dropped forwarded packets. */
2422 nat_ptr -> forwarded_packets_dropped++;
2423 #endif
2424
2425 /* Release the packet back to the packet pool. */
2426 nx_packet_release(packet_ptr);
2427
2428 /* Return the error status. */
2429 return status;
2430 }
2431
2432 /* OK to zero out the checksum field so we can update the header with a new checksum later. */
2433 udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 & ~NX_LOWER_16_MASK;
2434
2435 /* Did NAT assign a global UDP source port? */
2436 if (record_entry -> external_port != record_entry -> local_port)
2437 {
2438
2439 /* Yes, so replace local host UDP port with NAT global inside UDP port in the header. */
2440 udp_header_ptr -> nx_udp_header_word_0 = (udp_header_ptr -> nx_udp_header_word_0 & NX_LOWER_16_MASK) |
2441 (((ULONG) (record_entry -> external_port)) << NX_SHIFT_BY_16);
2442 }
2443
2444 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
2445 if(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_UDP_TX_CHECKSUM)
2446 compute_checksum = 0;
2447 else
2448 compute_checksum = 1;
2449 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
2450
2451 /* Get the old checksum. */
2452 checksum = udp_header_ptr -> nx_udp_header_word_1 & NX_LOWER_16_MASK;
2453
2454 /* UDP headers with 0 checksum should not be modified, RFC3022, Section4.1, Page8. */
2455 if (checksum == 0)
2456 compute_checksum = 0;
2457
2458 /* Compute the checksum. */
2459 if(compute_checksum)
2460 {
2461
2462 /* Check whether the port is updated. */
2463 if (record_entry -> external_port != record_entry -> local_port)
2464 {
2465
2466 /* Set the old port and new port. */
2467 old_port = record_entry -> local_port;
2468 new_port = record_entry -> external_port;
2469
2470 /* Adjust the checksum for port. */
2471 _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_port, sizeof(USHORT), (UCHAR *)&new_port, sizeof(USHORT));
2472 }
2473
2474 /* Set the old address and new address. */
2475 old_address = record_entry -> local_ip_address;
2476 new_address = nat_ptr -> nx_nat_ip_ptr -> nx_ip_interface[nat_ptr -> nx_nat_global_interface_index].nx_interface_ip_address;
2477
2478 /* Adjust the checksum for address. */
2479 _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_address, sizeof(LONG), (UCHAR *)&new_address, sizeof(LONG));
2480
2481 /* OK to clear the UDP checksum field to zero before the checksum update. */
2482 udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 & ~NX_LOWER_16_MASK;
2483
2484 /* Place the checksum into the first header word. */
2485 udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 | checksum;
2486 }
2487 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
2488 else
2489 {
2490
2491 /* OK to clear the UDP checksum field to zero before the checksum update. */
2492 udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 & ~NX_LOWER_16_MASK;
2493
2494 /* Set the flag. */
2495 packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_UDP_TX_CHECKSUM;
2496 }
2497 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
2498
2499 /* If NX_LITTLE_ENDIAN is defined, the headers need to be swapped to match
2500 that of the data area. */
2501 NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_0);
2502 NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1);
2503
2504 /* Send the UDP packet onto the global host. */
2505 _nx_nat_ip_packet_send(nat_ptr, packet_ptr, record_entry, NX_NAT_OUTBOUND_PACKET, next_hop_address);
2506
2507 /* Return packet send completion status. */
2508 return NX_SUCCESS;
2509 }
2510
2511
2512 /**************************************************************************/
2513 /* */
2514 /* FUNCTION RELEASE */
2515 /* */
2516 /* _nx_nat_process_outbound_ICMP_packet PORTABLE C */
2517 /* 6.1 */
2518 /* AUTHOR */
2519 /* */
2520 /* Yuxin Zhou, Microsoft Corporation */
2521 /* */
2522 /* DESCRIPTION */
2523 /* */
2524 /* This function processes a ICMP packet from a local network host for */
2525 /* sending out onto the external network. NAT replaces the private */
2526 /* source IP address and local query ID with a global source IP address */
2527 /* and query ID. NAT then recomputes the ICMP header checksum. */
2528 /* */
2529 /* INPUT */
2530 /* */
2531 /* nat_ptr Pointer to the NAT server */
2532 /* packet_ptr Pointer to the packet to process */
2533 /* entry_ptr Pointer to the entry */
2534 /* */
2535 /* OUTPUT */
2536 /* */
2537 /* status Actual completion status */
2538 /* NX_SUCCESS Successful completion status */
2539 /* NX_NAT_BAD_ICMP_CHECKSUM Packet failed ICMP checksum check */
2540 /* NX_NAT_INVALID_IP_HEADER Packet has an invalid IP header */
2541 /* */
2542 /* CALLS */
2543 /* */
2544 /* _nx_nat_outbound_entry_find Find outbound entry in entry list */
2545 /* _nx_nat_ip_packet_send Send packet to private interface */
2546 /* nx_packet_release Release the packet */
2547 /* */
2548 /* CALLED BY */
2549 /* */
2550 /* Application code */
2551 /* */
2552 /* RELEASE HISTORY */
2553 /* */
2554 /* DATE NAME DESCRIPTION */
2555 /* */
2556 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2557 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2558 /* resulting in version 6.1 */
2559 /* */
2560 /**************************************************************************/
_nx_nat_process_outbound_ICMP_packet(NX_NAT_DEVICE * nat_ptr,NX_PACKET * packet_ptr,NX_NAT_TRANSLATION_ENTRY * entry_ptr)2561 static UINT _nx_nat_process_outbound_ICMP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr)
2562 {
2563
2564 UINT status;
2565 ULONG sequence;
2566 UINT is_icmp_error_msg;
2567 NX_ICMP_HEADER *icmp_header_ptr;
2568 UINT type;
2569 USHORT old_port;
2570 USHORT new_port;
2571 USHORT checksum;
2572 ULONG compute_checksum;
2573 ULONG next_hop_address;
2574 NX_NAT_TRANSLATION_ENTRY *record_entry;
2575
2576
2577 /* Initialize local variables. */
2578 compute_checksum = 1;
2579
2580 /* Pickup the pointer to the head of the ICMP packet. */
2581 packet_ptr -> nx_packet_prepend_ptr += sizeof(NX_IPV4_HEADER);
2582 packet_ptr -> nx_packet_length -= sizeof(NX_IPV4_HEADER);
2583 icmp_header_ptr = (NX_ICMP_HEADER *)(packet_ptr -> nx_packet_prepend_ptr);
2584
2585 /* Swap ENDian-ness for our ICMP header. We've only swapped the IP header data so far. */
2586 NX_CHANGE_ULONG_ENDIAN(icmp_header_ptr -> nx_icmp_header_word_0);
2587 NX_CHANGE_ULONG_ENDIAN(icmp_header_ptr -> nx_icmp_header_word_1);
2588
2589 /* Extract the ICMP type and code. */
2590 type = icmp_header_ptr -> nx_icmp_header_word_0 >> 24;
2591
2592 /* Determine if this outbound packet an ICMP error message packet. */
2593 _nx_nat_packet_is_icmp_error_message(packet_ptr, &is_icmp_error_msg);
2594
2595 /* Is the this an error message packet? */
2596 if (is_icmp_error_msg)
2597 {
2598
2599 #ifndef NX_DISABLE_NAT_INFO
2600 /* Drop the packet and bail! */
2601 nat_ptr -> forwarded_packets_dropped++;
2602 #endif
2603
2604 /* Release the packet. */
2605 nx_packet_release(packet_ptr);
2606
2607 /* Return completion status. */
2608 return NX_SUCCESS;
2609 }
2610
2611 /* Find the outbound entry, set the packet global interface and next hop address. */
2612 status = _nx_nat_outbound_entry_find(nat_ptr, packet_ptr, entry_ptr, &record_entry, &next_hop_address);
2613
2614 /* Check for error. */
2615 if (status != NX_SUCCESS)
2616 {
2617
2618 #ifndef NX_DISABLE_NAT_INFO
2619 /* Increase the session count of dropped forwarded packets. */
2620 nat_ptr -> forwarded_packets_dropped++;
2621 #endif
2622
2623 /* Release the packet back to the packet pool. */
2624 nx_packet_release(packet_ptr);
2625
2626 /* Return the error status. */
2627 return status;
2628 }
2629
2630 /* Update the ICMP Query ID ("port") if the NAT device mapped it to another Query ID
2631 but not if this is a local host responding to a REQUEST ICMP packet, in which case
2632 it must keep the same Query ID. */
2633 if ((type != NX_ICMP_ECHO_REPLY_TYPE) && (record_entry -> external_port != record_entry -> local_port))
2634 {
2635
2636 /* Pick up the ICMP sequence number. */
2637 sequence = icmp_header_ptr -> nx_icmp_header_word_1 & NX_LOWER_16_MASK;
2638
2639 /* Set the ICMP Query ID in the ICMP header. */
2640 icmp_header_ptr -> nx_icmp_header_word_1 = (ULONG) (record_entry -> external_port << NX_SHIFT_BY_16) | sequence;
2641
2642 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
2643 if(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_ICMPV4_TX_CHECKSUM)
2644 compute_checksum = 0;
2645 else
2646 compute_checksum = 1;
2647 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
2648 if(compute_checksum)
2649 {
2650
2651 /* Set the old checksum. */
2652 checksum = icmp_header_ptr -> nx_icmp_header_word_0 & NX_LOWER_16_MASK;
2653
2654 /* Set the old port and new port. */
2655 old_port = record_entry -> local_port;
2656 new_port = record_entry -> external_port;
2657
2658 /* Adjust the checksum. */
2659 _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_port, sizeof(USHORT), (UCHAR *)&new_port, sizeof(USHORT));
2660
2661 /* Ok to zero out the checksum because we'll replace it with an updated checksum. */
2662 icmp_header_ptr -> nx_icmp_header_word_0 = icmp_header_ptr -> nx_icmp_header_word_0 & ~NX_LOWER_16_MASK;
2663
2664 /* Place the checksum into the first header word. */
2665 icmp_header_ptr -> nx_icmp_header_word_0 = icmp_header_ptr -> nx_icmp_header_word_0 | checksum;
2666 }
2667 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
2668 else
2669 {
2670
2671 /* Set the checksum to zero. */
2672 icmp_header_ptr -> nx_icmp_header_word_0 = icmp_header_ptr -> nx_icmp_header_word_0 & ~NX_LOWER_16_MASK;
2673
2674 /* Set the flag. */
2675 packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_ICMPV4_TX_CHECKSUM;
2676 }
2677 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
2678 }
2679
2680 /* If NX_LITTLE_ENDIAN is defined, the headers need to be swapped to match
2681 that of the data area. */
2682 NX_CHANGE_ULONG_ENDIAN(icmp_header_ptr -> nx_icmp_header_word_0);
2683 NX_CHANGE_ULONG_ENDIAN(icmp_header_ptr -> nx_icmp_header_word_1);
2684
2685 /* Send the ICMP packet onto the global host. */
2686 _nx_nat_ip_packet_send(nat_ptr, packet_ptr, record_entry, NX_NAT_OUTBOUND_PACKET, next_hop_address);
2687
2688 /* Return completion status. */
2689 return NX_SUCCESS;
2690 }
2691
2692
2693 /**************************************************************************/
2694 /* */
2695 /* FUNCTION RELEASE */
2696 /* */
2697 /* _nx_nat_ip_packet_send PORTABLE C */
2698 /* 6.1 */
2699 /* AUTHOR */
2700 /* */
2701 /* Yuxin Zhou, Microsoft Corporation */
2702 /* */
2703 /* DESCRIPTION */
2704 /* */
2705 /* This function is the NAT equivalent of nx_ip_packet_send. It handles */
2706 /* all packets inbound or outbound of any protocol and forwards them */
2707 /* directly to the driver. */
2708 /* */
2709 /* This function also handles fragmented datagrams. */
2710 /* */
2711 /* INPUT */
2712 /* */
2713 /* nat_ptr Pointer to NAT server */
2714 /* packet_ptr Pointer to packet */
2715 /* entry_ptr Pointer to NAT entry */
2716 /* packet_type Packet type(inbound/outbound) */
2717 /* next_hop_address Next hop address to target */
2718 /* */
2719 /* OUTPUT */
2720 /* */
2721 /* status Actual completion status. */
2722 /* NX_SUCCESS Successful completion status */
2723 /* NX_NAT_FRAGMENT_QUEUE_NOT_FOUND Fragment queue for datagram */
2724 /* not found */
2725 /* CALLS */
2726 /* */
2727 /* nx_packet_release Release the packet */
2728 /* _nx_packet_data_append Append the overflow data */
2729 /* _nx_nat_checksum_adjust Adjust checksum for NAT changes */
2730 /* to IP header */
2731 /* _nx_ip_driver_packet_send Forward packet to driver to send*/
2732 /* */
2733 /* CALLED BY */
2734 /* */
2735 /* _nx_nat_process_outbound_TCP_packet Process outbound TCP packet */
2736 /* _nx_nat_process_outbound_UDP_packet Process outbound UDP packet */
2737 /* _nx_nat_process_outbound_ICMP_packet Process outbound ICMP packet */
2738 /* _nx_nat_process_inbound_TCP_packet Process outbound TCP packet */
2739 /* _nx_nat_process_inbound_UDP_packet Process outbound UDP packet */
2740 /* _nx_nat_process_inbound_ICMP_packet Process outbound ICMP packet */
2741 /* */
2742 /* RELEASE HISTORY */
2743 /* */
2744 /* DATE NAME DESCRIPTION */
2745 /* */
2746 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2747 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2748 /* resulting in version 6.1 */
2749 /* */
2750 /**************************************************************************/
_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)2751 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)
2752 {
2753
2754 ULONG fragment_bits;
2755 ULONG old_address;
2756 ULONG new_address;
2757 ULONG old_fragment;
2758 ULONG new_fragment;
2759 USHORT checksum;
2760 ULONG compute_checksum = 1;
2761 ULONG destination_ip;
2762 UINT status;
2763 NX_IPV4_HEADER *ip_header_ptr;
2764
2765
2766 /* Pickup the pointer to the head of the ICMP packet. */
2767 packet_ptr -> nx_packet_prepend_ptr -= sizeof(NX_IPV4_HEADER);
2768 packet_ptr -> nx_packet_length += sizeof(NX_IPV4_HEADER);
2769 ip_header_ptr = (NX_IPV4_HEADER *) (packet_ptr -> nx_packet_prepend_ptr);
2770
2771 /* Check the packet type. */
2772 if (packet_type == NX_NAT_OUTBOUND_PACKET)
2773 {
2774
2775 /* Update the source ip address. */
2776 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;
2777
2778 /* Set the local address and external address. */
2779 old_address = entry_ptr -> local_ip_address;
2780 new_address = nat_ptr -> nx_nat_ip_ptr -> nx_ip_interface[nat_ptr -> nx_nat_global_interface_index].nx_interface_ip_address;
2781 }
2782 else
2783 {
2784 /* Update the destination ip address. */
2785 ip_header_ptr -> nx_ip_header_destination_ip = entry_ptr -> local_ip_address;
2786
2787 /* Set the old address and new address. */
2788 old_address = nat_ptr -> nx_nat_ip_ptr -> nx_ip_interface[nat_ptr -> nx_nat_global_interface_index].nx_interface_ip_address;
2789 new_address = entry_ptr -> local_ip_address;
2790 }
2791
2792 /* Record the destination IP address. */
2793 destination_ip = ip_header_ptr -> nx_ip_header_destination_ip;
2794
2795 /* Record the fragment bit. */
2796 fragment_bits = (ip_header_ptr -> nx_ip_header_word_1 & NX_IP_DONT_FRAGMENT);
2797 old_fragment = ip_header_ptr -> nx_ip_header_word_1 & NX_LOWER_16_MASK;
2798 new_fragment = old_fragment;
2799
2800 /* Check if the packet is fragmented and if the fragment field is not zero. */
2801 if ((fragment_bits != NX_IP_DONT_FRAGMENT) && (old_fragment != 0))
2802 {
2803
2804 /* Clear the fragment field. */
2805 ip_header_ptr -> nx_ip_header_word_1 = ip_header_ptr -> nx_ip_header_word_1 & ~NX_LOWER_16_MASK;
2806 new_fragment = 0;
2807 }
2808
2809 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
2810 if(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_IPV4_TX_CHECKSUM)
2811 compute_checksum = 0;
2812 else
2813 compute_checksum = 1;
2814 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
2815
2816 /* Compute the checksum. */
2817 if(compute_checksum)
2818 {
2819
2820 /* Get the checksum. */
2821 checksum = ip_header_ptr -> nx_ip_header_word_2 & NX_LOWER_16_MASK;
2822
2823 /* Adjust the checksum for address. */
2824 _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_address, sizeof(LONG), (UCHAR *)&new_address, sizeof(LONG));
2825
2826 /* Check if the fragment field is updated. */
2827 if (old_fragment != new_fragment)
2828 {
2829
2830 /* Adjust the checksum for fragment field. */
2831 _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_fragment, sizeof(LONG), (UCHAR *)&new_fragment, sizeof(LONG));
2832 }
2833
2834 /* Clear the checksum value. */
2835 ip_header_ptr -> nx_ip_header_word_2 = ip_header_ptr -> nx_ip_header_word_2 & ~NX_LOWER_16_MASK;
2836
2837 /* Place the checksum into the header word. */
2838 ip_header_ptr -> nx_ip_header_word_2 = ip_header_ptr -> nx_ip_header_word_2 | checksum;
2839 }
2840 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
2841 else
2842 {
2843
2844 /* Clear the checksum value. */
2845 ip_header_ptr -> nx_ip_header_word_2 = ip_header_ptr -> nx_ip_header_word_2 & ~NX_LOWER_16_MASK;
2846
2847 /* Set the flag. */
2848 packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_IPV4_TX_CHECKSUM;
2849 }
2850 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
2851
2852 /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will
2853 swap the endian of the IP header. */
2854 NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_0);
2855 NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_1);
2856 NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_2);
2857 NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_source_ip);
2858 NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_destination_ip);
2859
2860 /* Check if the packet can fill physical header. */
2861 status = _nx_packet_data_adjust(packet_ptr, NX_PHYSICAL_HEADER);
2862
2863 /* Check status. */
2864 if (status)
2865 {
2866
2867 #ifndef NX_DISABLE_NAT_INFO
2868 /* Update the count. */
2869 nat_ptr -> forwarded_packets_dropped ++;
2870 #endif
2871
2872 /* Release the packet. */
2873 _nx_packet_release(packet_ptr);
2874 return;
2875 }
2876
2877 #ifndef NX_DISABLE_NAT_INFO
2878 /* Update the packet sent count. */
2879 nat_ptr -> forwarded_packets_sent++;
2880 #endif
2881
2882 /* Call the function to directly forward the packet. */
2883 _nx_ip_driver_packet_send(nat_ptr -> nx_nat_ip_ptr, packet_ptr, destination_ip, fragment_bits, next_hop_address);
2884 return;
2885 }
2886
2887
2888 /**************************************************************************/
2889 /* */
2890 /* FUNCTION RELEASE */
2891 /* */
2892 /* _nx_nat_inbound_entry_find PORTABLE C */
2893 /* 6.1 */
2894 /* AUTHOR */
2895 /* */
2896 /* Yuxin Zhou, Microsoft Corporation */
2897 /* */
2898 /* DESCRIPTION */
2899 /* */
2900 /* This function finds the inbound entry in NAT translation entry list, */
2901 /* */
2902 /* INPUT */
2903 /* */
2904 /* nat_ptr Pointer to NAT server */
2905 /* packet_ptr Pointer to packet */
2906 /* entry_ptr Pointer to NAT entry */
2907 /* entry_ptr Pointer to the matched entry */
2908 /* next_hop_address The next hop address for route */
2909 /* */
2910 /* OUTPUT */
2911 /* */
2912 /* NX_SUCCESS Successful completion status */
2913 /* */
2914 /* CALLS */
2915 /* */
2916 /* _nx_nat_utility_get_source_port Extract source port from packet */
2917 /* _nx_nat_utility_get_destination_port */
2918 /* Extract destination port from */
2919 /* packet */
2920 /* _nx_nat_entry_create Create entry for packet in NAT */
2921 /* translation table */
2922 /* _nx_nat_entry_find Find the entry */
2923 /* _nx_ip_route_find Find the suitable interface */
2924 /* */
2925 /* CALLED BY */
2926 /* */
2927 /* _nx_nat_process_inbound_TCP_packet Process outbound TCP packet */
2928 /* _nx_nat_process_inbound_UDP_packet Process outbound UDP packet */
2929 /* _nx_nat_process_inbound_ICMP_packet Process outbound ICMP packet */
2930 /* */
2931 /* RELEASE HISTORY */
2932 /* */
2933 /* DATE NAME DESCRIPTION */
2934 /* */
2935 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
2936 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
2937 /* resulting in version 6.1 */
2938 /* */
2939 /**************************************************************************/
_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)2940 static UINT _nx_nat_inbound_entry_find(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr,
2941 NX_NAT_TRANSLATION_ENTRY **matched_entry_ptr, ULONG *next_hop_address)
2942 {
2943
2944 UINT status;
2945 ULONG timeout;
2946 NX_NAT_TRANSLATION_ENTRY *record_entry;
2947
2948
2949 /* Check the protocol. */
2950 if ((entry_ptr -> protocol == NX_PROTOCOL_TCP) || (entry_ptr -> protocol == NX_PROTOCOL_UDP))
2951 {
2952
2953 /* Get sender's source port. */
2954 _nx_nat_utility_get_source_port(packet_ptr, entry_ptr -> protocol, &entry_ptr -> peer_port);
2955 }
2956
2957 /* Get the destination port from header data. */
2958 _nx_nat_utility_get_destination_port(packet_ptr, entry_ptr -> protocol, &entry_ptr -> external_port);
2959
2960 /* Check the timeout for all dynamic entries. */
2961 _nx_nat_entry_timeout_check(nat_ptr);
2962
2963 /* Now search the table for a matching NAT translation entry. */
2964 _nx_nat_entry_find(nat_ptr, entry_ptr, &record_entry, NX_NAT_INBOUND_PACKET, NX_TRUE);
2965
2966 /* Was a matching entry found in our translation table? */
2967 if (!record_entry)
2968 {
2969
2970 /* Next see if the destination is a local host server. */
2971
2972 /* Find a 'server' for packet destination IP address and port */
2973 _nx_nat_entry_find(nat_ptr, entry_ptr, &record_entry, NX_NAT_INBOUND_PACKET, NX_FALSE);
2974
2975 /* Check the record entry. */
2976 if (record_entry)
2977 {
2978
2979 /* We found a matching server entry in the table. Now create an
2980 entry specifically for this packet. */
2981
2982 /* Get the private IP address from the entry we just found, and apply to the new entry we're creating. */
2983 entry_ptr -> local_ip_address = record_entry -> local_ip_address;
2984
2985 /* Check the private inside port. */
2986 if (record_entry -> local_port == 0)
2987 {
2988
2989 /* Set the private inside port same as global inside port. */
2990 entry_ptr -> local_port = entry_ptr -> external_port;
2991 }
2992 else
2993 {
2994
2995 /* Set private inside port. */
2996 entry_ptr -> local_port = record_entry -> local_port;
2997 }
2998
2999 /* Set the entry expiration timeout. */
3000 if (entry_ptr -> protocol == NX_PROTOCOL_TCP)
3001 {
3002
3003 /* TCP session. */
3004 timeout = NX_NAT_TCP_SESSION_TIMEOUT;
3005 }
3006 else
3007 {
3008
3009 /* Non-TCP session. */
3010 timeout = NX_NAT_NON_TCP_SESSION_TIMEOUT;
3011 }
3012
3013 /* Now create the entry. */
3014 status = _nx_nat_entry_create(nat_ptr, entry_ptr -> protocol,
3015 entry_ptr -> local_ip_address,
3016 entry_ptr -> peer_ip_address,
3017 entry_ptr -> local_port,
3018 entry_ptr -> external_port,
3019 entry_ptr -> peer_port,
3020 timeout,
3021 &record_entry);
3022
3023 /* Check for error. */
3024 if (status != NX_SUCCESS)
3025 {
3026
3027 /* Return status.*/
3028 return status;
3029 }
3030 }
3031 else
3032 {
3033
3034 /* Return status.*/
3035 return (NX_NAT_ENTRY_NOT_FOUND);
3036 }
3037 }
3038
3039 /* Clear the packet interface as private interface. */
3040 packet_ptr -> nx_packet_address.nx_packet_interface_ptr = NX_NULL;
3041
3042 /* Set the inbound interface and next hop address. */
3043 if(_nx_ip_route_find(nat_ptr -> nx_nat_ip_ptr, record_entry -> local_ip_address,
3044 &packet_ptr -> nx_packet_address.nx_packet_interface_ptr, next_hop_address) != NX_SUCCESS)
3045 {
3046
3047 /* No suitable private interface configured. */
3048
3049 /* Return the error status. */
3050 return (NX_NAT_ROUTE_FIND_ERROR);
3051 }
3052
3053 /* Set the matched entry pointer. */
3054 *matched_entry_ptr = record_entry;
3055
3056 /* Return success. */
3057 return (NX_SUCCESS);
3058 }
3059
3060
3061 /**************************************************************************/
3062 /* */
3063 /* FUNCTION RELEASE */
3064 /* */
3065 /* _nx_nat_outbound_entry_find PORTABLE C */
3066 /* 6.1 */
3067 /* AUTHOR */
3068 /* */
3069 /* Yuxin Zhou, Microsoft Corporation */
3070 /* */
3071 /* DESCRIPTION */
3072 /* */
3073 /* This function finds the outbound entry in NAT translation entry list.*/
3074 /* */
3075 /* INPUT */
3076 /* */
3077 /* nat_ptr Pointer to NAT server */
3078 /* packet_ptr Pointer to packet */
3079 /* entry_ptr Pointer to NAT entry */
3080 /* entry_ptr Pointer to the matched entry */
3081 /* next_hop_address The next hop address for route */
3082 /* */
3083 /* OUTPUT */
3084 /* */
3085 /* NX_SUCCESS Successful completion status */
3086 /* */
3087 /* CALLS */
3088 /* */
3089 /* _nx_nat_utility_get_source_port Extract source port from packet */
3090 /* _nx_nat_utility_get_destination_port */
3091 /* Extract destination port from */
3092 /* packet */
3093 /* _nx_nat_entry_create Create entry for packet in NAT */
3094 /* translation table */
3095 /* _nx_nat_entry_find Find the entry */
3096 /* _nx_ip_route_find Find the suitable interface */
3097 /* */
3098 /* CALLED BY */
3099 /* */
3100 /* _nx_nat_process_outbound_TCP_packet Process outbound TCP packet */
3101 /* _nx_nat_process_outbound_UDP_packet Process outbound UDP packet */
3102 /* _nx_nat_process_outbound_ICMP_packet Process outbound ICMP packet */
3103 /* */
3104 /* RELEASE HISTORY */
3105 /* */
3106 /* DATE NAME DESCRIPTION */
3107 /* */
3108 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3109 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3110 /* resulting in version 6.1 */
3111 /* */
3112 /**************************************************************************/
_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)3113 static UINT _nx_nat_outbound_entry_find(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr,
3114 NX_NAT_TRANSLATION_ENTRY **matched_entry_ptr, ULONG *next_hop_address)
3115 {
3116
3117 UINT status;
3118 ULONG timeout;
3119 NX_NAT_TRANSLATION_ENTRY *record_entry;
3120
3121
3122 /* Get source ports from the header. */
3123 _nx_nat_utility_get_source_port(packet_ptr, entry_ptr -> protocol, &(entry_ptr -> local_port));
3124
3125 /* Check the protocol. */
3126 if ((entry_ptr -> protocol == NX_PROTOCOL_TCP) || (entry_ptr -> protocol == NX_PROTOCOL_UDP))
3127 {
3128
3129 /* Get destination port from the header. */
3130 _nx_nat_utility_get_destination_port(packet_ptr, entry_ptr -> protocol, &(entry_ptr -> peer_port));
3131 }
3132
3133 /* Check the timeout for all dynamic entries. */
3134 _nx_nat_entry_timeout_check(nat_ptr);
3135
3136 /* Search the table for a match. */
3137 _nx_nat_entry_find(nat_ptr, entry_ptr, &record_entry, NX_NAT_OUTBOUND_PACKET, NX_TRUE);
3138
3139 /* Was a matching table entry found? */
3140 if (!record_entry)
3141 {
3142
3143 /* Find the available port. */
3144 status = _nx_nat_find_available_port(nat_ptr, entry_ptr -> protocol, &entry_ptr -> external_port);
3145
3146 /* Check for error. */
3147 if (status != NX_SUCCESS)
3148 {
3149
3150 return status;
3151 }
3152
3153 /* Set the entry expiration timeout. */
3154 if (entry_ptr -> protocol == NX_PROTOCOL_TCP)
3155 {
3156
3157 /* TCP session. */
3158 timeout = NX_NAT_TCP_SESSION_TIMEOUT;
3159 }
3160 else
3161 {
3162
3163 /* Non-TCP session. */
3164 timeout = NX_NAT_NON_TCP_SESSION_TIMEOUT;
3165 }
3166
3167 /* Create an entry with NAT translation for IP address/port. */
3168 status = _nx_nat_entry_create(nat_ptr, entry_ptr -> protocol,
3169 entry_ptr -> local_ip_address,
3170 entry_ptr -> peer_ip_address,
3171 entry_ptr -> local_port,
3172 entry_ptr -> external_port,
3173 entry_ptr -> peer_port,
3174 timeout,
3175 &record_entry);
3176
3177 /* Check for error. */
3178 if (status != NX_SUCCESS)
3179 {
3180
3181 /* Return error status. */
3182 return status;
3183 }
3184 }
3185
3186 /* Set the packet interface as global interface. */
3187 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]);
3188
3189 /* Set the next hop address. */
3190 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)
3191 {
3192
3193 /* No suitable private interface configured. */
3194
3195 /* Return the error status. */
3196 return (NX_NAT_ROUTE_FIND_ERROR);
3197 }
3198
3199 /* Set the matched entry pointer. */
3200 *matched_entry_ptr = record_entry;
3201
3202 /* Return success. */
3203 return (NX_SUCCESS);
3204 }
3205
3206
3207 /**************************************************************************/
3208 /* */
3209 /* FUNCTION RELEASE */
3210 /* */
3211 /* _nx_nat_entry_create PORTABLE C */
3212 /* 6.1 */
3213 /* AUTHOR */
3214 /* */
3215 /* Yuxin Zhou, Microsoft Corporation */
3216 /* */
3217 /* DESCRIPTION */
3218 /* */
3219 /* This function dynamically creates a NAT translation table entry */
3220 /* and appends the entry to the translation list. */
3221 /* */
3222 /* INPUT */
3223 /* */
3224 /* nat_ptr Pointer to NAT instance */
3225 /* protocol Protocol of packets matching entry*/
3226 /* local_ip_address Entry's private IP address */
3227 /* peer_ip_address Entry's external host IP */
3228 /* local_port Entry's private port */
3229 /* external_port Entry's global port */
3230 /* peer_port Entry's external port (optional) */
3231 /* response_timeout Entry expiration timeout */
3232 /* match_entry_ptr Pointer to entry created */
3233 /* */
3234 /* OUTPUT */
3235 /* */
3236 /* status Actual completion status */
3237 /* NX_SUCCESS Successful completion status */
3238 /* NX_NAT_TRANSLATION_TABLE_FULL Table is full (max capacity) */
3239 /* NX_NAT_INVALID_TABLE_ENTRY Invalid criteria for table entry */
3240 /* */
3241 /* CALLS */
3242 /* */
3243 /* _nx_nat_entry_add Add entry to linked list of entries*/
3244 /* memset Clear specified area of memory */
3245 /* */
3246 /* CALLED BY */
3247 /* */
3248 /* _nx_nat_inbound_entry_find Find inbound entry in entry list */
3249 /* _nx_nat_outbound_entry_find Find outbound entry in entry list */
3250 /* */
3251 /* RELEASE HISTORY */
3252 /* */
3253 /* DATE NAME DESCRIPTION */
3254 /* */
3255 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3256 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3257 /* resulting in version 6.1 */
3258 /* */
3259 /**************************************************************************/
_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)3260 static UINT _nx_nat_entry_create(NX_NAT_DEVICE *nat_ptr, UCHAR protocol,
3261 ULONG local_ip_address, ULONG peer_ip_address,
3262 USHORT local_port, USHORT external_port, USHORT peer_port,
3263 ULONG response_timeout, NX_NAT_TRANSLATION_ENTRY **match_entry_ptr)
3264 {
3265
3266 NX_NAT_TRANSLATION_ENTRY *insert_entry_ptr = NX_NULL;
3267
3268 #ifdef NX_NAT_ENABLE_REPLACEMENT
3269 NX_NAT_TRANSLATION_ENTRY *insert_previous_ptr = NX_NULL;
3270 NX_NAT_TRANSLATION_ENTRY *entry_ptr = NX_NULL;
3271 NX_NAT_TRANSLATION_ENTRY *previous_ptr = NX_NULL;
3272 #endif /* NX_NAT_ENABLE_REPLACEMENT */
3273
3274
3275 /* Initialize result to not found. */
3276 *match_entry_ptr = NX_NULL;
3277
3278 /* Perform some simple sanity checks on this entry. */
3279
3280 /* Was an invalid IP address submitted? */
3281 if ((peer_ip_address == 0x0) ||
3282 (local_ip_address == 0x0))
3283 {
3284
3285 return (NX_NAT_INVALID_ENTRY);
3286 }
3287
3288 /* Check available entries. */
3289 if (nat_ptr -> nx_nat_dynamic_available_entries)
3290 {
3291
3292 /* Get one available entry. */
3293 insert_entry_ptr = nat_ptr -> nx_nat_dynamic_available_entry_head;
3294
3295 /* Update the entry head. */
3296 nat_ptr -> nx_nat_dynamic_available_entry_head = insert_entry_ptr -> next_entry_ptr;
3297 }
3298 else
3299 {
3300 #ifdef NX_NAT_ENABLE_REPLACEMENT
3301
3302 /* Get a pointer to the start of the entries in the translation table. */
3303 entry_ptr = nat_ptr -> nx_nat_dynamic_active_entry_head;
3304
3305 /* Search the whole entry list to find the oldest non-TCP entry. */
3306 while (entry_ptr)
3307 {
3308
3309 /* Check the entry type and protocol. */
3310 if ((entry_ptr -> translation_type == NX_NAT_STATIC_ENTRY) || (entry_ptr -> protocol == NX_PROTOCOL_TCP))
3311 {
3312
3313 /* Ingore this entry, Get the next entry in the table. */
3314 previous_ptr = entry_ptr;
3315 entry_ptr = entry_ptr -> next_entry_ptr;
3316 continue;
3317 }
3318 else
3319 {
3320
3321 /* Check if set the insert_entry_ptr(oldest entry). */
3322 if (insert_entry_ptr == NX_NULL)
3323 {
3324
3325 /* Assume the first entry is the oldest entry. */
3326 insert_entry_ptr = entry_ptr;
3327 insert_previous_ptr = previous_ptr;
3328 }
3329 else
3330 {
3331
3332 /* Compare the timestamp. */
3333 if (((INT)insert_entry_ptr -> response_timestamp - (INT)entry_ptr -> response_timestamp) > 0)
3334 {
3335
3336 /* entry_ptr is an older entry, so update the insert_entry_ptr. */
3337 insert_entry_ptr = entry_ptr;
3338 insert_previous_ptr = previous_ptr;
3339 }
3340 }
3341
3342 /* Get the next entry in the table. */
3343 previous_ptr = entry_ptr;
3344 entry_ptr = entry_ptr -> next_entry_ptr;
3345 }
3346 }
3347
3348 /* Check if found the oldest non-TCP entry. */
3349 if (insert_entry_ptr)
3350 {
3351
3352 /* Yes, found it. Check if this is the first entry in the list. */
3353 if (insert_previous_ptr)
3354 {
3355
3356 /* It is not, so link the previous entry around the entry we are deleting. */
3357 insert_previous_ptr -> next_entry_ptr = insert_entry_ptr -> next_entry_ptr;
3358 }
3359 else
3360 {
3361
3362 /* It is the first entry, so set the next pointer as the starting translation table entry. */
3363 nat_ptr -> nx_nat_dynamic_active_entry_head = insert_entry_ptr -> next_entry_ptr;
3364 }
3365
3366 /* Update the entry count. */
3367 nat_ptr -> nx_nat_dynamic_active_entries --;
3368 nat_ptr -> nx_nat_dynamic_available_entries ++;
3369 }
3370 else
3371 {
3372 #endif /* NX_NAT_ENABLE_REPLACEMENT */
3373
3374 /* This service cache does not have room for the entry. */
3375 /* Invoke user-installed cache full notify function .*/
3376 if(nat_ptr -> nx_nat_cache_full_notify)
3377 {
3378
3379 /* Call the callback function. */
3380 (nat_ptr -> nx_nat_cache_full_notify)(nat_ptr);
3381 }
3382
3383 /* Return error status. */
3384 return (NX_NAT_CACHE_FULL);
3385
3386 #ifdef NX_NAT_ENABLE_REPLACEMENT
3387 }
3388 #endif /* NX_NAT_ENABLE_REPLACEMENT */
3389 }
3390
3391 /* Initialize the allocated memory to NULL. */
3392 memset(insert_entry_ptr, 0, sizeof(NX_NAT_TRANSLATION_ENTRY));
3393
3394 /* Assign the entry attributes. */
3395 insert_entry_ptr -> protocol = protocol;
3396 insert_entry_ptr -> local_ip_address = local_ip_address;
3397 insert_entry_ptr -> peer_ip_address = peer_ip_address;
3398 insert_entry_ptr -> local_port = local_port;
3399 insert_entry_ptr -> external_port = external_port;
3400 insert_entry_ptr -> peer_port = peer_port;
3401 insert_entry_ptr -> response_timeout = response_timeout;
3402
3403 /* Set the entry timestamp. */
3404 insert_entry_ptr -> response_timestamp = tx_time_get();
3405
3406 /* Set entry type to dynamically created. */
3407 insert_entry_ptr -> translation_type = NX_NAT_DYNAMIC_ENTRY;
3408
3409 /* Append to the table. */
3410 _nx_nat_entry_add(nat_ptr, insert_entry_ptr);
3411
3412 /* Set a pointer to the newly created entry. */
3413 *match_entry_ptr = insert_entry_ptr;
3414
3415 /* Return successful completion status. */
3416 return (NX_SUCCESS);
3417 }
3418
3419
3420 /**************************************************************************/
3421 /* */
3422 /* FUNCTION RELEASE */
3423 /* */
3424 /* _nx_nat_entry_add PORTABLE C */
3425 /* 6.1 */
3426 /* AUTHOR */
3427 /* */
3428 /* Yuxin Zhou, Microsoft Corporation */
3429 /* */
3430 /* DESCRIPTION */
3431 /* */
3432 /* This function adds a NAT translation entry to the NAT entry list */
3433 /* */
3434 /* INPUT */
3435 /* */
3436 /* nat_ptr Pointer to NAT instance */
3437 /* entry_ptr Pointer to NAT translation entry */
3438 /* */
3439 /* OUTPUT */
3440 /* */
3441 /* NX_SUCCESS Successful completion status */
3442 /* */
3443 /* CALLS */
3444 /* */
3445 /* None */
3446 /* */
3447 /* CALLED BY */
3448 /* */
3449 /* _nx_nat_inbound_entry_create Create inbound entry to NAT table */
3450 /* before starting the NAT server */
3451 /* _nx_nat_entry_create Create and add entry to NAT table */
3452 /* after starting the NAT server */
3453 /* */
3454 /* RELEASE HISTORY */
3455 /* */
3456 /* DATE NAME DESCRIPTION */
3457 /* */
3458 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3459 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3460 /* resulting in version 6.1 */
3461 /* */
3462 /**************************************************************************/
_nx_nat_entry_add(NX_NAT_DEVICE * nat_ptr,NX_NAT_TRANSLATION_ENTRY * entry_ptr)3463 static UINT _nx_nat_entry_add(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr)
3464 {
3465
3466
3467 /* Add this entry onto the table entry list. */
3468 entry_ptr -> next_entry_ptr = nat_ptr -> nx_nat_dynamic_active_entry_head;
3469 nat_ptr -> nx_nat_dynamic_active_entry_head = entry_ptr;
3470
3471 /* Update the entry count. */
3472 if (entry_ptr -> translation_type == NX_NAT_DYNAMIC_ENTRY)
3473 {
3474
3475 /* Update the entry count. */
3476 nat_ptr -> nx_nat_dynamic_active_entries ++;
3477 nat_ptr -> nx_nat_dynamic_available_entries --;
3478 }
3479 else
3480 nat_ptr -> nx_nat_static_active_entries ++;
3481
3482 /* Return success status. */
3483 return(NX_SUCCESS);
3484 }
3485
3486
3487 /**************************************************************************/
3488 /* */
3489 /* FUNCTION RELEASE */
3490 /* */
3491 /* _nx_nat_entry_find PORTABLE C */
3492 /* 6.1 */
3493 /* AUTHOR */
3494 /* */
3495 /* Yuxin Zhou, Microsoft Corporation */
3496 /* */
3497 /* DESCRIPTION */
3498 /* */
3499 /* This function attempts to find an entry in the NAT translation list */
3500 /* that matches the entry submitted by the caller. If none is found it*/
3501 /* returns a null pointer. There is an option to skip entries */
3502 /* designated for local hosts accepting packets from external hosts */
3503 /* (e.g. servers). */
3504 /* */
3505 /* INPUT */
3506 /* */
3507 /* nat_ptr Pointer to NAT server */
3508 /* entry_to_match Pointer to entry to match in the list */
3509 /* match_entry_ptr Pointer to matching entry in the list */
3510 /* direction Forward direction(inbound/outbound) */
3511 /* skip_inbound_init_entries Skip entries for local hosts allowing */
3512 /* initial packet from external source */
3513 /* */
3514 /* OUTPUT */
3515 /* */
3516 /* NX_SUCCESS Successful completion status */
3517 /* status Actual completion status */
3518 /* */
3519 /* CALLS */
3520 /* */
3521 /* tx_time_get Get the system time */
3522 /* */
3523 /* CALLED BY */
3524 /* */
3525 /* _nx_nat_inbound_entry_find Find inbound entry in entry list */
3526 /* _nx_nat_outbound_entry_find Find outbound entry in entry list */
3527 /* */
3528 /* RELEASE HISTORY */
3529 /* */
3530 /* DATE NAME DESCRIPTION */
3531 /* */
3532 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3533 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3534 /* resulting in version 6.1 */
3535 /* */
3536 /**************************************************************************/
_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)3537 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,
3538 UCHAR direction, UINT skip_static_entries)
3539 {
3540
3541 NX_NAT_TRANSLATION_ENTRY *entry_ptr;
3542 NX_NAT_TRANSLATION_ENTRY *previous_ptr;
3543
3544
3545 /* Initialize the search result to null (no match found). */
3546 *match_entry_ptr = 0x0;
3547
3548 /* Check the inbound entry. */
3549 if ((direction == NX_NAT_INBOUND_PACKET) &&
3550 (!entry_to_match -> peer_ip_address))
3551 {
3552
3553 /* Return. */
3554 return;
3555 }
3556
3557 /* Check the outbound entry. */
3558 if ((direction == NX_NAT_OUTBOUND_PACKET) &&
3559 ((!entry_to_match -> local_ip_address) || (!entry_to_match -> peer_ip_address)))
3560 {
3561
3562 /* Return. */
3563 return ;
3564 }
3565
3566 /* Initialize the previous pointer. */
3567 previous_ptr = NX_NULL;
3568
3569 /* Get a pointer to the start of the entries in the translation table. */
3570 entry_ptr = nat_ptr -> nx_nat_dynamic_active_entry_head;
3571
3572 /* Search the whole table until a match is found. */
3573 while (entry_ptr)
3574 {
3575
3576 /* Check the entry type, (e.g. accepts packets from external hosts) ?*/
3577 if ((entry_ptr -> translation_type == NX_NAT_STATIC_ENTRY) && (skip_static_entries == NX_TRUE))
3578 {
3579
3580 /* Set the previous entry pointer. */
3581 previous_ptr = entry_ptr;
3582
3583 /* Ingore the static entry, get the next entry in the table. */
3584 entry_ptr = entry_ptr -> next_entry_ptr;
3585
3586 continue;
3587 }
3588
3589 /* Do sender and entry protocols match? */
3590 if (entry_ptr -> protocol != entry_to_match -> protocol)
3591 {
3592
3593 /* Set the previous entry pointer. */
3594 previous_ptr = entry_ptr;
3595
3596 /* Get the next entry in the table. */
3597 entry_ptr = entry_ptr -> next_entry_ptr;
3598
3599 continue;
3600 }
3601
3602 /* Continue matching IP address and port criteria. */
3603
3604 /* Do external IP addresses, if specified, match? */
3605 if ((entry_ptr -> peer_ip_address) &&
3606 (entry_ptr -> peer_ip_address != entry_to_match -> peer_ip_address))
3607 {
3608
3609 /* Set the previous entry pointer. */
3610 previous_ptr = entry_ptr;
3611
3612 /* No, get the next entry. */
3613 entry_ptr = entry_ptr -> next_entry_ptr;
3614
3615 continue;
3616 }
3617
3618 /* Do external ports, if specified match? */
3619 if ((entry_ptr -> peer_port) &&
3620 (entry_ptr -> peer_port != entry_to_match -> peer_port))
3621 {
3622
3623 /* Set the previous entry pointer. */
3624 previous_ptr = entry_ptr;
3625
3626 /* No, get the next entry in the table. */
3627 entry_ptr = entry_ptr -> next_entry_ptr;
3628
3629 continue;
3630 }
3631
3632 /* Check the inbound entry. */
3633 if (direction == NX_NAT_INBOUND_PACKET)
3634 {
3635
3636 /* Does the inside host global port, if specified, match? */
3637 if ((entry_ptr -> external_port) &&
3638 (entry_ptr -> external_port != entry_to_match -> external_port))
3639 {
3640
3641 /* Set the previous entry pointer. */
3642 previous_ptr = entry_ptr;
3643
3644 /* No, get the next entry in the table. */
3645 entry_ptr = entry_ptr -> next_entry_ptr;
3646
3647 continue;
3648 }
3649 }
3650 else
3651 {
3652
3653 /* Do private inside IP addresses, if specified, match? */
3654 if ((entry_ptr -> local_ip_address) &&
3655 (entry_ptr -> local_ip_address != entry_to_match -> local_ip_address))
3656 {
3657
3658 /* Set the previous entry pointer. */
3659 previous_ptr = entry_ptr;
3660
3661 /* No, get the next entry in the table. */
3662 entry_ptr = entry_ptr -> next_entry_ptr;
3663
3664 continue;
3665 }
3666
3667 /* Does the inside host private port, if specified, match? */
3668 if ((entry_ptr -> local_port) &&
3669 (entry_ptr -> local_port != entry_to_match -> local_port))
3670 {
3671
3672 /* Set the previous entry pointer. */
3673 previous_ptr = entry_ptr;
3674
3675 /* No, get the next entry in the table. */
3676 entry_ptr = entry_ptr -> next_entry_ptr;
3677
3678 continue;
3679 }
3680 }
3681
3682 /* If we got this far, all criteria matched up. Set a pointer to
3683 this entry in the table. */
3684 *match_entry_ptr = entry_ptr;
3685
3686 /* The entry is active, reset the timeout to the present. */
3687 entry_ptr -> response_timestamp = tx_time_get();
3688
3689 /* Yes; check if this is the first entry in the list. */
3690 if (previous_ptr)
3691 {
3692
3693 /* It is not. Put this entry at the head of the list to improve searching effectiveness. */
3694 previous_ptr -> next_entry_ptr = entry_ptr -> next_entry_ptr;
3695 entry_ptr -> next_entry_ptr = nat_ptr -> nx_nat_dynamic_active_entry_head;
3696 nat_ptr -> nx_nat_dynamic_active_entry_head = entry_ptr;
3697 }
3698 break;
3699 }
3700 return;
3701 }
3702
3703
3704 /**************************************************************************/
3705 /* */
3706 /* FUNCTION RELEASE */
3707 /* */
3708 /* _nx_nat_entry_timeout_check PORTABLE C */
3709 /* 6.1 */
3710 /* AUTHOR */
3711 /* */
3712 /* Yuxin Zhou, Microsoft Corporation */
3713 /* */
3714 /* DESCRIPTION */
3715 /* */
3716 /* This function attempts to check the entry's timeout, and remove the */
3717 /* expiration entries from dynamic active translation list. */
3718 /* */
3719 /* INPUT */
3720 /* */
3721 /* nat_ptr Pointer to NAT server */
3722 /* */
3723 /* OUTPUT */
3724 /* */
3725 /* NX_SUCCESS Successful completion status */
3726 /* */
3727 /* CALLS */
3728 /* */
3729 /* tx_time_get Get the system time */
3730 /* */
3731 /* CALLED BY */
3732 /* */
3733 /* _nx_nat_inbound_entry_find Find inbound entry in entry list */
3734 /* _nx_nat_outbound_entry_find Find outbound entry in entry list */
3735 /* */
3736 /* RELEASE HISTORY */
3737 /* */
3738 /* DATE NAME DESCRIPTION */
3739 /* */
3740 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3741 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3742 /* resulting in version 6.1 */
3743 /* */
3744 /**************************************************************************/
_nx_nat_entry_timeout_check(NX_NAT_DEVICE * nat_ptr)3745 static VOID _nx_nat_entry_timeout_check(NX_NAT_DEVICE *nat_ptr)
3746 {
3747
3748 ULONG current_time;
3749 ULONG elapsed_time;
3750 NX_NAT_TRANSLATION_ENTRY *entry_ptr;
3751 NX_NAT_TRANSLATION_ENTRY *previous_ptr;
3752 NX_NAT_TRANSLATION_ENTRY *next_entry_ptr;
3753
3754
3755 /* Get the current time. */
3756 current_time = tx_time_get();
3757
3758 /* Get a pointer to the start of the entries in the translation table. */
3759 entry_ptr = nat_ptr -> nx_nat_dynamic_active_entry_head;
3760
3761 /* Initialize the previous pointer. */
3762 previous_ptr = NX_NULL;
3763
3764 /* Search thru the whole entry list. */
3765 while (entry_ptr)
3766 {
3767
3768 /* Set a pointer to the next entry in the table. */
3769 next_entry_ptr = entry_ptr -> next_entry_ptr;
3770
3771 /* Check the entry type and update the time. */
3772 if (entry_ptr -> translation_type == NX_NAT_DYNAMIC_ENTRY)
3773 {
3774
3775 /* Calculate the elapsed time. */
3776 elapsed_time = current_time - entry_ptr -> response_timestamp;
3777
3778 /* Update the time remaining. */
3779 if (elapsed_time >= entry_ptr -> response_timeout)
3780 {
3781
3782 /* Delete this entry from active entry list. */
3783
3784 /* Check if this is the first entry in the list). */
3785 if (previous_ptr)
3786 {
3787
3788 /* It is not, so link the previous entry around the entry we are deleting. */
3789 previous_ptr -> next_entry_ptr = next_entry_ptr;
3790 }
3791 else
3792 {
3793
3794 /* It is the first entry, so set the next pointer as the starting translation table entry. */
3795 nat_ptr -> nx_nat_dynamic_active_entry_head = next_entry_ptr;
3796 }
3797
3798 /* Add the entry onto available entry list. */
3799 entry_ptr -> next_entry_ptr = nat_ptr -> nx_nat_dynamic_available_entry_head;
3800 nat_ptr -> nx_nat_dynamic_available_entry_head = entry_ptr;
3801
3802 /* Update the entry count. */
3803 nat_ptr -> nx_nat_dynamic_active_entries --;
3804 nat_ptr -> nx_nat_dynamic_available_entries ++;
3805 }
3806 else
3807 {
3808
3809 /* Set the previous entry. */
3810 previous_ptr = entry_ptr;
3811 }
3812 }
3813 else
3814 {
3815
3816 /* Set the previous entry. */
3817 previous_ptr = entry_ptr;
3818 }
3819
3820 /* Get the next entry in the table. */
3821 entry_ptr = next_entry_ptr;
3822 }
3823
3824 return;
3825 }
3826
3827
3828 /**************************************************************************/
3829 /* */
3830 /* FUNCTION RELEASE */
3831 /* */
3832 /* _nx_nat_utility_get_destination_port PORTABLE C */
3833 /* 6.1 */
3834 /* AUTHOR */
3835 /* */
3836 /* Yuxin Zhou, Microsoft Corporation */
3837 /* */
3838 /* DESCRIPTION */
3839 /* */
3840 /* This function extracts the destination port from the packet's */
3841 /* protocol header. In the case of ICMP packets, it extracts the ICMP */
3842 /* header identifier (ID) instead. */
3843 /* */
3844 /* INPUT */
3845 /* */
3846 /* packet_ptr Pointer to packet with destination port */
3847 /* protocol Packet protocol (TCP, UDP etc) */
3848 /* peer_port Pointer to external (destination) port */
3849 /* */
3850 /* OUTPUT */
3851 /* */
3852 /* NX_SUCCESS Successful completion status */
3853 /* */
3854 /* CALLS */
3855 /* */
3856 /* _nx_nat_packet_is_icmp_error_message */
3857 /* Indicate if ICMP packet is query or */
3858 /* error message packet */
3859 /* */
3860 /* CALLED BY */
3861 /* */
3862 /* _nx_nat_inbound_entry_find Find inbound entry in entry list */
3863 /* _nx_nat_outbound_entry_find Find outbound entry in entry list */
3864 /* */
3865 /* RELEASE HISTORY */
3866 /* */
3867 /* DATE NAME DESCRIPTION */
3868 /* */
3869 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3870 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3871 /* resulting in version 6.1 */
3872 /* */
3873 /**************************************************************************/
_nx_nat_utility_get_destination_port(NX_PACKET * packet_ptr,UCHAR protocol,USHORT * peer_port)3874 static UINT _nx_nat_utility_get_destination_port(NX_PACKET *packet_ptr, UCHAR protocol, USHORT *peer_port)
3875 {
3876
3877 NX_TCP_HEADER *tcp_header_ptr;
3878 NX_UDP_HEADER *udp_header_ptr;
3879 NX_ICMP_HEADER *icmp_header_ptr;
3880 UINT is_icmp_error_msg;
3881
3882
3883 /* Is this a TCP packet? */
3884 if (protocol == NX_PROTOCOL_TCP)
3885 {
3886
3887 /* Pickup the pointer to the head of the TCP packet. */
3888 tcp_header_ptr = (NX_TCP_HEADER *)(packet_ptr -> nx_packet_prepend_ptr);
3889
3890 /* Pickup the destination TCP port. */
3891 *peer_port = (USHORT) (tcp_header_ptr -> nx_tcp_header_word_0 & NX_LOWER_16_MASK);
3892 }
3893 /* Is this a UDP packet? */
3894 else if (protocol == NX_PROTOCOL_UDP)
3895 {
3896
3897 /* Pickup the pointer to the head of the UDP packet. */
3898 udp_header_ptr = (NX_UDP_HEADER *)(packet_ptr -> nx_packet_prepend_ptr);
3899
3900 /* Pickup the destination UDP port. */
3901 *peer_port = (USHORT) (udp_header_ptr -> nx_udp_header_word_0 & NX_LOWER_16_MASK);
3902 }
3903 /* Is this an ICMP packet? */
3904 else if (protocol == NX_PROTOCOL_ICMP)
3905 {
3906
3907 /* Determin type of ICMP message. */
3908 _nx_nat_packet_is_icmp_error_message(packet_ptr, &is_icmp_error_msg);
3909
3910 /* Is this an ICMP error message? */
3911 if (is_icmp_error_msg )
3912 {
3913
3914 /* Yes, these don't have query ID fields. */
3915 *peer_port = 0;
3916 }
3917 else
3918 {
3919
3920 /* Setup the pointer to the ICMP header located in the data area after the IP header. */
3921 icmp_header_ptr = (NX_ICMP_HEADER *) (packet_ptr -> nx_packet_prepend_ptr);
3922
3923 /* Pickup the ICMP identifier which we will call the 'source port'. */
3924 *peer_port = (USHORT) (icmp_header_ptr -> nx_icmp_header_word_1 >> NX_SHIFT_BY_16);
3925 }
3926 }
3927 else
3928 {
3929
3930 /* Unknown or unsupported packet protocol. */
3931 *peer_port = 0;
3932 }
3933
3934 return NX_SUCCESS;
3935 }
3936
3937
3938 /**************************************************************************/
3939 /* */
3940 /* FUNCTION RELEASE */
3941 /* */
3942 /* _nx_nat_utility_get_source_port PORTABLE C */
3943 /* 6.1 */
3944 /* AUTHOR */
3945 /* */
3946 /* Yuxin Zhou, Microsoft Corporation */
3947 /* */
3948 /* DESCRIPTION */
3949 /* */
3950 /* This function extracts the source port from the packet's protocol */
3951 /* header. In the case of ICMP packets, it extracts the query identifier*/
3952 /* (ID) instead. */
3953 /* */
3954 /* INPUT */
3955 /* */
3956 /* packet_ptr Pointer to packet to get source port */
3957 /* protocol Packet protocol (TCP, UDP etc) */
3958 /* source_port Pointer to packet source port */
3959 /* */
3960 /* OUTPUT */
3961 /* */
3962 /* NX_SUCCESS Successful completion status */
3963 /* */
3964 /* CALLS */
3965 /* */
3966 /* _nx_nat_packet_is_icmp_error_message */
3967 /* Indicate if ICMP packet is query or */
3968 /* error message ICMP packet */
3969 /* */
3970 /* CALLED BY */
3971 /* */
3972 /* _nx_nat_inbound_entry_find Find inbound entry in entry list */
3973 /* _nx_nat_outbound_entry_find Find outbound entry in entry list */
3974 /* */
3975 /* RELEASE HISTORY */
3976 /* */
3977 /* DATE NAME DESCRIPTION */
3978 /* */
3979 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
3980 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
3981 /* resulting in version 6.1 */
3982 /* */
3983 /**************************************************************************/
_nx_nat_utility_get_source_port(NX_PACKET * packet_ptr,UCHAR protocol,USHORT * source_port)3984 static UINT _nx_nat_utility_get_source_port(NX_PACKET *packet_ptr, UCHAR protocol, USHORT *source_port)
3985 {
3986
3987 NX_TCP_HEADER *tcp_header_ptr;
3988 NX_UDP_HEADER *udp_header_ptr;
3989 NX_ICMP_HEADER *icmp_header_ptr;
3990 UINT is_icmp_error_msg;
3991
3992 if (protocol == NX_PROTOCOL_TCP)
3993 {
3994
3995 /* Pickup the pointer to the head of the TCP packet. */
3996 tcp_header_ptr = (NX_TCP_HEADER *)(packet_ptr -> nx_packet_prepend_ptr);
3997
3998 /* Pickup the source TCP port. */
3999 *source_port = (USHORT) (tcp_header_ptr -> nx_tcp_header_word_0 >> NX_SHIFT_BY_16);
4000 }
4001 else if (protocol == NX_PROTOCOL_UDP)
4002 {
4003
4004 /* Pickup the pointer to the head of the UDP packet. */
4005 udp_header_ptr = (NX_UDP_HEADER *)(packet_ptr -> nx_packet_prepend_ptr);
4006
4007 /* Pickup the source UDP port. */
4008 *source_port = (USHORT) (udp_header_ptr -> nx_udp_header_word_0 >> NX_SHIFT_BY_16);
4009 }
4010 else if (protocol == NX_PROTOCOL_ICMP)
4011 {
4012
4013 /* Determine type of ICMP message. */
4014 _nx_nat_packet_is_icmp_error_message(packet_ptr, &is_icmp_error_msg);
4015
4016 /* Is this an ICMP error message? */
4017 if (is_icmp_error_msg )
4018 {
4019
4020 /* Yes, return a zero query ID (error messages have no Query ID). */
4021 *source_port = 0;
4022 }
4023 else
4024 {
4025
4026 /* Setup the pointer to the ICMP header located in the data area after the IP header. */
4027 icmp_header_ptr = (NX_ICMP_HEADER *) (packet_ptr -> nx_packet_prepend_ptr);
4028
4029 /* Pickup the ICMP Query ID which is used in place of a source port. */
4030 *source_port = (USHORT)(icmp_header_ptr -> nx_icmp_header_word_1 >> NX_SHIFT_BY_16);
4031 }
4032 }
4033 else
4034 /* Unknown or unsupported protocol. */
4035 *source_port = 0;
4036
4037 return NX_SUCCESS;
4038 }
4039
4040
4041 /**************************************************************************/
4042 /* */
4043 /* FUNCTION RELEASE */
4044 /* */
4045 /* _nx_nat_find_available_port PORTABLE C */
4046 /* 6.1 */
4047 /* AUTHOR */
4048 /* */
4049 /* Yuxin Zhou, Microsoft Corporation */
4050 /* */
4051 /* DESCRIPTION */
4052 /* */
4053 /* This function finds an available a ICMP query identifier (ID) or */
4054 /* or TCP/UDP port when NAT is configured to share a global IP address */
4055 /* among its local hosts and consequently must use the query ID/port */
4056 /* field to uniquely identify. */
4057 /* */
4058 /* INPUT */
4059 /* */
4060 /* nat_ptr Pointer to NAT instance */
4061 /* protocol Network protocol(TCP, UDP, ICMP) */
4062 /* port Pointer to an unused port */
4063 /* */
4064 /* OUTPUT */
4065 /* */
4066 /* NX_SUCCESS Successful completion status */
4067 /* NX_NAT_NO_FREE_PORT_AVAILABLE No free port found status */
4068 /* status Actual completion status */
4069 /* */
4070 /* CALLS */
4071 /* */
4072 /* None */
4073 /* */
4074 /* CALLED BY */
4075 /* */
4076 /* _nx_nat_outbound_entry_find Find outbound entry in entry list */
4077 /* */
4078 /* RELEASE HISTORY */
4079 /* */
4080 /* DATE NAME DESCRIPTION */
4081 /* */
4082 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4083 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4084 /* resulting in version 6.1 */
4085 /* */
4086 /**************************************************************************/
_nx_nat_find_available_port(NX_NAT_DEVICE * nat_ptr,UCHAR protocol,USHORT * port)4087 static UINT _nx_nat_find_available_port(NX_NAT_DEVICE *nat_ptr, UCHAR protocol, USHORT *port)
4088 {
4089
4090 UINT bound;
4091 USHORT start_port;
4092 USHORT end_port;
4093 NX_NAT_TRANSLATION_ENTRY *entry_ptr;
4094
4095
4096 /* Start at the lowest of number for translated query ID/port for NAT. */
4097 if (protocol == NX_PROTOCOL_TCP)
4098 {
4099 start_port = NX_NAT_START_TCP_PORT;
4100 end_port = NX_NAT_END_TCP_PORT;
4101 }
4102 else if(protocol == NX_PROTOCOL_UDP)
4103 {
4104 start_port = NX_NAT_START_UDP_PORT;
4105 end_port = NX_NAT_END_UDP_PORT;
4106 }
4107 else
4108 {
4109 start_port = NX_NAT_START_ICMP_QUERY_ID;
4110 end_port = NX_NAT_END_ICMP_QUERY_ID;
4111 }
4112
4113 /* Set the start port. */
4114 *port = start_port;
4115
4116 /* Search for a Query ID not found in the translation table. */
4117 while(*port < end_port)
4118 {
4119
4120 /* Initialize the bound flag. */
4121 bound = NX_FALSE;
4122
4123 /* Serach dynamic entries. */
4124 entry_ptr = nat_ptr -> nx_nat_dynamic_active_entry_head;
4125
4126 /* Loop through the whole translation table. */
4127 while(entry_ptr)
4128 {
4129
4130 /* Check the protocol. */
4131 if (entry_ptr -> protocol == protocol)
4132 {
4133
4134 /* Does this entry have a matching port ID. */
4135 if (entry_ptr -> external_port == *port)
4136 {
4137
4138 /* Set the flag so we can abort the current search. */
4139 bound = NX_TRUE;
4140 break;
4141 }
4142 }
4143
4144 /* Get the next entry in the table. */
4145 entry_ptr = entry_ptr -> next_entry_ptr;
4146 }
4147
4148 /* Check if we got through the entire table with no bound port. */
4149 if ((bound == NX_FALSE) &&
4150 ((protocol == NX_PROTOCOL_TCP) || (protocol == NX_PROTOCOL_UDP)))
4151 {
4152
4153 /* Yes, check the NetXDuo TCP/UDP socket. */
4154 bound = _nx_nat_socket_port_verify(nat_ptr -> nx_nat_ip_ptr, protocol, *port);
4155 }
4156
4157 /* Check if we found a socket with a matching port. */
4158 if (bound == NX_FALSE)
4159 {
4160
4161 /* We did not. OK to use this port. */
4162 return NX_SUCCESS;
4163 }
4164
4165 /* Found a match. This port is not available. */
4166
4167 /* Bump the port up one. */
4168 (*port)++;
4169 }
4170
4171 /* If we got here we could not find a free port. */
4172 return (NX_NAT_NO_FREE_PORT_AVAILABLE);
4173 }
4174
4175
4176 /**************************************************************************/
4177 /* */
4178 /* FUNCTION RELEASE */
4179 /* */
4180 /* _nx_nat_entry_port_verify PORTABLE C */
4181 /* 6.1 */
4182 /* AUTHOR */
4183 /* */
4184 /* Yuxin Zhou, Microsoft Corporation */
4185 /* */
4186 /* DESCRIPTION */
4187 /* */
4188 /* This function verifies whether the supplied port is bound. lookup */
4189 /* all NAT translation entries, If same ports are found, return */
4190 /* NX_TRUE, else return NX_FALSE. */
4191 /* */
4192 /* INPUT */
4193 /* */
4194 /* ip_ptr IP instance pointer */
4195 /* protocol Protocol */
4196 /* port Port */
4197 /* */
4198 /* OUTPUT */
4199 /* */
4200 /* bound Completion status */
4201 /* NX_TRUE: port is bound */
4202 /* NX_FALSE: port is not bound */
4203 /* */
4204 /* CALLS */
4205 /* */
4206 /* none */
4207 /* */
4208 /* CALLED BY */
4209 /* */
4210 /* Application Code */
4211 /* */
4212 /* RELEASE HISTORY */
4213 /* */
4214 /* DATE NAME DESCRIPTION */
4215 /* */
4216 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4217 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4218 /* resulting in version 6.1 */
4219 /* */
4220 /**************************************************************************/
_nx_nat_entry_port_verify(NX_IP * ip_ptr,UINT protocol,UINT port)4221 static UINT _nx_nat_entry_port_verify(NX_IP *ip_ptr, UINT protocol, UINT port)
4222 {
4223
4224 UINT bound;
4225 NX_NAT_TRANSLATION_ENTRY *entry_ptr;
4226
4227 NX_PARAMETER_NOT_USED(ip_ptr);
4228
4229 /* Initialize the return value. */
4230 bound = NX_FALSE;
4231
4232 /* Serach dynamic entries. */
4233 entry_ptr = nat_server_ptr -> nx_nat_dynamic_active_entry_head;
4234
4235 /* Loop through the whole translation table. */
4236 while(entry_ptr)
4237 {
4238
4239 /* Check the protocol. */
4240 if (entry_ptr -> protocol == protocol)
4241 {
4242
4243 /* Does this entry have a matching port ID. */
4244 if (entry_ptr -> external_port == port)
4245 {
4246
4247 /* Set the flag so we can abort the current search. */
4248 bound = NX_TRUE;
4249 break;
4250 }
4251 }
4252
4253 /* Get the next entry in the table. */
4254 entry_ptr = entry_ptr -> next_entry_ptr;
4255 }
4256
4257 /* Return status to the caller. */
4258 return(bound);
4259 }
4260
4261
4262 /**************************************************************************/
4263 /* */
4264 /* FUNCTION RELEASE */
4265 /* */
4266 /* _nx_nat_socket_port_verify PORTABLE C */
4267 /* 6.1 */
4268 /* AUTHOR */
4269 /* */
4270 /* Yuxin Zhou, Microsoft Corporation */
4271 /* */
4272 /* DESCRIPTION */
4273 /* */
4274 /* This function verifies whether the supplied port is bound. Search */
4275 /* all TCP/UDP sockets, and if the port is found, return NX_TRUE, */
4276 /* else return NX_TRUE. */
4277 /* */
4278 /* INPUT */
4279 /* */
4280 /* ip_ptr IP instance pointer */
4281 /* protocol Protocol */
4282 /* port Port */
4283 /* */
4284 /* OUTPUT */
4285 /* */
4286 /* bound Completion status */
4287 /* NX_TRUE: port is bound */
4288 /* NX_FALSE: port is not bound */
4289 /* */
4290 /* CALLS */
4291 /* */
4292 /* none */
4293 /* */
4294 /* CALLED BY */
4295 /* */
4296 /* Application Code */
4297 /* */
4298 /* RELEASE HISTORY */
4299 /* */
4300 /* DATE NAME DESCRIPTION */
4301 /* */
4302 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4303 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4304 /* resulting in version 6.1 */
4305 /* */
4306 /**************************************************************************/
_nx_nat_socket_port_verify(NX_IP * ip_ptr,UINT protocol,UINT port)4307 static UINT _nx_nat_socket_port_verify(NX_IP *ip_ptr, UINT protocol, UINT port)
4308 {
4309
4310 UINT index;
4311 UINT bound;
4312 NX_TCP_SOCKET *tcp_search_ptr;
4313 NX_TCP_SOCKET *tcp_end_ptr;
4314 NX_UDP_SOCKET *udp_search_ptr;
4315 NX_UDP_SOCKET *udp_end_ptr;
4316
4317
4318 /* Initialize the return value. */
4319 bound = NX_FALSE;
4320
4321 /* Check the protocol. */
4322 if (protocol == NX_PROTOCOL_TCP)
4323 {
4324
4325 /* Calculate the hash index in the TCP port array of the associated IP instance. */
4326 index = (UINT) ((port + (port >> 8)) & NX_TCP_PORT_TABLE_MASK);
4327
4328 /* Pickup the head of the TCP ports bound list. */
4329 tcp_search_ptr = ip_ptr -> nx_ip_tcp_port_table[index];
4330
4331 /* Determine if we need to perform a list search. */
4332 if (tcp_search_ptr)
4333 {
4334
4335 /* Walk through the circular list of UDP sockets that are already bound. */
4336 tcp_end_ptr = tcp_search_ptr;
4337 do
4338 {
4339
4340 /* Determine if this entry is the same as the requested port. */
4341 if (tcp_search_ptr -> nx_tcp_socket_port == port)
4342 {
4343
4344 /* Yes, the port has already been bound. */
4345 bound = NX_TRUE;
4346 break;
4347 }
4348
4349 /* Move to the next entry in the list. */
4350 tcp_search_ptr = tcp_search_ptr -> nx_tcp_socket_bound_next;
4351
4352 } while (tcp_search_ptr != tcp_end_ptr);
4353 }
4354 }
4355 else
4356 {
4357
4358 /* Calculate the hash index in the UDP port array of the associated IP instance. */
4359 index = (UINT) ((port + (port >> 8)) & NX_UDP_PORT_TABLE_MASK);
4360
4361 /* Pickup the head of the UDP ports bound list. */
4362 udp_search_ptr = ip_ptr -> nx_ip_udp_port_table[index];
4363
4364 /* Determine if we need to perform a list search. */
4365 if (udp_search_ptr)
4366 {
4367
4368 /* Walk through the circular list of UDP sockets that are already bound. */
4369 udp_end_ptr = udp_search_ptr;
4370 do
4371 {
4372
4373 /* Determine if this entry is the same as the requested port. */
4374 if (udp_search_ptr -> nx_udp_socket_port == port)
4375 {
4376
4377 /* Yes, the port has already been bound. */
4378 bound = NX_TRUE;
4379 break;
4380 }
4381
4382 /* Move to the next entry in the list. */
4383 udp_search_ptr = udp_search_ptr -> nx_udp_socket_bound_next;
4384
4385 } while (udp_search_ptr != udp_end_ptr);
4386 }
4387 }
4388
4389 /* Return success to the caller. */
4390 return(bound);
4391 }
4392
4393
4394 /**************************************************************************/
4395 /* */
4396 /* FUNCTION RELEASE */
4397 /* */
4398 /* _nx_nat_packet_is_icmp_error_message PORTABLE C */
4399 /* 6.1 */
4400 /* AUTHOR */
4401 /* */
4402 /* Yuxin Zhou, Microsoft Corporation */
4403 /* */
4404 /* DESCRIPTION */
4405 /* */
4406 /* This function determines if an ICMP packet is a query message or an */
4407 /* error message. */
4408 /* */
4409 /* INPUT */
4410 /* */
4411 /* packet_ptr Pointer to ICMP packet to parse */
4412 /* is_icmp_error_msg Indicates if packet is an error */
4413 /* message packet */
4414 /* OUTPUT */
4415 /* */
4416 /* NX_SUCCESS Successful completion status */
4417 /* */
4418 /* CALLS */
4419 /* */
4420 /* None */
4421 /* */
4422 /* CALLED BY */
4423 /* */
4424 /* _nx_nat_process_inbound_ICMP_packet Forward inbound ICMP packets */
4425 /* _nx_nat_process_outbound_ICMP_packet Forward outbound ICMP packets */
4426 /* _nx_nat_utility_get_source_port Extract source port from header*/
4427 /* _nx_nat_utility_get_destination_port Extract destination port from */
4428 /* header */
4429 /* */
4430 /* RELEASE HISTORY */
4431 /* */
4432 /* DATE NAME DESCRIPTION */
4433 /* */
4434 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4435 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4436 /* resulting in version 6.1 */
4437 /* */
4438 /**************************************************************************/
_nx_nat_packet_is_icmp_error_message(NX_PACKET * packet_ptr,UINT * is_icmp_error_msg)4439 static UINT _nx_nat_packet_is_icmp_error_message(NX_PACKET *packet_ptr, UINT *is_icmp_error_msg)
4440 {
4441
4442 UINT type;
4443 UINT protocol;
4444 NX_IPV4_HEADER *ip_header_ptr;
4445 NX_ICMP_HEADER *icmp_header_ptr;
4446
4447
4448 /* Initialize the result to non error message type. */
4449 *is_icmp_error_msg = NX_FALSE;
4450
4451 /* Set up an IP header pointer to the packet. */
4452 ip_header_ptr = (NX_IPV4_HEADER *) (packet_ptr -> nx_packet_prepend_ptr - sizeof(NX_IPV4_HEADER));
4453
4454 /* Set up an ICMP header pointer to the packet. */
4455 icmp_header_ptr = (NX_ICMP_HEADER *) (packet_ptr -> nx_packet_prepend_ptr);
4456
4457 /* Determine what protocol the current IP datagram is. */
4458 protocol = (ip_header_ptr -> nx_ip_header_word_2 >> 16) & 0xFF;
4459
4460 /* Is this an ICMP packet? */
4461 if (protocol == NX_PROTOCOL_ICMP)
4462 {
4463
4464 /* Extract the ICMP type and code. */
4465 type = icmp_header_ptr -> nx_icmp_header_word_0 >> 24;
4466
4467 /* Determine if this is an error message. */
4468 if (type != NX_ICMP_ECHO_REPLY_TYPE &&
4469 type != NX_ICMP_ECHO_REQUEST_TYPE &&
4470 type < NX_ICMP_TIMESTAMP_REQ_TYPE)
4471 {
4472
4473 /* It is. Set the flag to true. */
4474 *is_icmp_error_msg = NX_TRUE;
4475 }
4476 }
4477
4478 /* Return successful completion status. */
4479 return NX_SUCCESS;
4480 }
4481
4482
4483 /**************************************************************************/
4484 /* */
4485 /* FUNCTION RELEASE */
4486 /* */
4487 /* _nx_nat_checksum_adjust PORTABLE C */
4488 /* 6.1 */
4489 /* AUTHOR */
4490 /* */
4491 /* Yuxin Zhou, Microsoft Corporation */
4492 /* */
4493 /* DESCRIPTION */
4494 /* */
4495 /* This function is an optimization for recomputing a checksum by just */
4496 /* computing the difference where a small amount of data has changed. */
4497 /* NAT uses this optimization when, for example, it is only changing an */
4498 /* IP address or port. */
4499 /* */
4500 /* INPUT */
4501 /* old_checksum Pointer to the old checksum */
4502 /* old_data Pointer to the data being changed*/
4503 /* new_data Pointer to new data replacing the*/
4504 /* old data */
4505 /* data_adjustment_length Size of data being changed */
4506 /* adjusted_checksum Pointer to the updated checksum */
4507 /* */
4508 /* OUTPUT */
4509 /* */
4510 /* NX_SUCCESS Successful completion status */
4511 /* */
4512 /* CALLS */
4513 /* */
4514 /* None */
4515 /* */
4516 /* CALLED BY */
4517 /* */
4518 /* _nx_nat_process_inbound_TCP_packet Send TCP packet to local host */
4519 /* _nx_nat_process_inbound_UDP_packet Send UDP packet to local host */
4520 /* _nx_nat_process_inbound_ICMP_packet Send ICMP packet to local host */
4521 /* _nx_nat_process_outbound_TCP_packet Send TCP packet to external host */
4522 /* _nx_nat_process_outbound_UDP_packet Send UDP packet to external host */
4523 /* _nx_nat_process_outbound_ICMP_packet Send ICMP packet to external host*/
4524 /* */
4525 /* RELEASE HISTORY */
4526 /* */
4527 /* DATE NAME DESCRIPTION */
4528 /* */
4529 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
4530 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
4531 /* resulting in version 6.1 */
4532 /* */
4533 /**************************************************************************/
_nx_nat_checksum_adjust(UCHAR * checksum,UCHAR * old_data,INT old_data_length,UCHAR * new_data,INT new_data_length)4534 static VOID _nx_nat_checksum_adjust(UCHAR *checksum, UCHAR *old_data, INT old_data_length, UCHAR *new_data, INT new_data_length)
4535 {
4536
4537 LONG x, old_value, new_value;
4538 INT i,j;
4539
4540 #ifdef NX_LITTLE_ENDIAN
4541 i = 1;
4542 j = 0;
4543 #else
4544 i = 0;
4545 j = 1;
4546 #endif
4547
4548 /* Checksum Adjustment, RFC 3022, Section 4.2, Page 9. */
4549
4550 /* Get the old checksum. */
4551 x = checksum[i] * 256 + checksum[j];
4552 x = ~x & 0xFFFF;
4553
4554 /* Update the checksum for old data. */
4555 while (old_data_length)
4556 {
4557
4558 /* Get the old data. */
4559 old_value = old_data[i] * 256 + old_data[j];
4560
4561 /* Update the old data pointer. */
4562 old_data += 2;
4563
4564 /* Update the checksum. */
4565 x -= old_value & 0xFFFF;
4566
4567 /* Check the value. */
4568 if (x <= 0)
4569 {
4570
4571 /* Update the value. */
4572 x --;
4573 x &= 0xFFFF;
4574 }
4575
4576 /* Update the old data length. */
4577 old_data_length -= 2;
4578 }
4579
4580 /* Update the checksum for new data. */
4581 while (new_data_length)
4582 {
4583
4584 /* Get the new data. */
4585 new_value = new_data[i] * 256 + new_data[j];
4586
4587 /* Update the new data pointer. */
4588 new_data += 2;
4589
4590 /* Update the checksum. */
4591 x += new_value & 0xFFFF;
4592
4593 /* Check the value. */
4594 if (x & 0x10000)
4595 {
4596
4597 /* Update the value. */
4598 x ++;
4599 x &= 0xFFFF;
4600 }
4601
4602 /* Update the new data length. */
4603 new_data_length -= 2;
4604 }
4605
4606 /* Update the value. */
4607 x = ~x & 0xFFFF;
4608
4609 /* Update the checksum. */
4610 checksum[i] = (UCHAR)(x /256);
4611 checksum[j] = (UCHAR)(x & 0xFF);
4612
4613 /* Return. */
4614 return;
4615 }
4616 #endif
4617