ipnat.c revision 1.1.1.1 1 /* $NetBSD: ipnat.c,v 1.1.1.1 2012/03/23 21:20:25 christos Exp $ */
2
3 /*
4 * Copyright (C) 2011 by Darren Reed.
5 *
6 * See the IPFILTER.LICENCE file for details on licencing.
7 *
8 * Added redirect stuff and a variety of bug fixes. (mcn (at) EnGarde.com)
9 */
10 #include <stdio.h>
11 #include <string.h>
12 #include <fcntl.h>
13 #include <errno.h>
14 #include <sys/types.h>
15 #if !defined(__SVR4) && !defined(__svr4__)
16 #include <strings.h>
17 #else
18 #include <sys/byteorder.h>
19 #endif
20 #include <sys/time.h>
21 #include <sys/param.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <stddef.h>
25 #include <sys/file.h>
26 #define _KERNEL
27 #include <sys/uio.h>
28 #undef _KERNEL
29 #include <sys/socket.h>
30 #include <sys/ioctl.h>
31 #if defined(sun) && (defined(__svr4__) || defined(__SVR4))
32 # include <sys/ioccom.h>
33 # include <sys/sysmacros.h>
34 #endif
35 #include <netinet/in.h>
36 #include <netinet/in_systm.h>
37 #include <netinet/ip.h>
38 #include <netinet/tcp.h>
39 #include <net/if.h>
40 #if __FreeBSD_version >= 300000
41 # include <net/if_var.h>
42 #endif
43 #include <netdb.h>
44 #include <arpa/nameser.h>
45 #include <arpa/inet.h>
46 #include <resolv.h>
47 #include <ctype.h>
48 #if defined(linux)
49 # include <linux/a.out.h>
50 #else
51 # include <nlist.h>
52 #endif
53 #include "ipf.h"
54 #include "netinet/ipl.h"
55 #include "kmem.h"
56
57 #ifdef __hpux
58 # define nlist nlist64
59 #endif
60
61 #if defined(sun) && !SOLARIS2
62 # define STRERROR(x) sys_errlist[x]
63 extern char *sys_errlist[];
64 #else
65 # define STRERROR(x) strerror(x)
66 #endif
67
68 #if !defined(lint)
69 static const char sccsid[] ="@(#)ipnat.c 1.9 6/5/96 (C) 1993 Darren Reed";
70 static const char rcsid[] = "@(#)Id";
71 #endif
72
73
74 #if SOLARIS
75 #define bzero(a,b) memset(a,0,b)
76 #endif
77 int use_inet6 = 0;
78 char thishost[MAXHOSTNAMELEN];
79
80 extern char *optarg;
81
82 void dostats __P((int, natstat_t *, int, int, int *));
83 void dotable __P((natstat_t *, int, int, int, char *));
84 void flushtable __P((int, int, int *));
85 void usage __P((char *));
86 int main __P((int, char*[]));
87 void showhostmap __P((natstat_t *nsp));
88 void natstat_dead __P((natstat_t *, char *));
89 void dostats_live __P((int, natstat_t *, int, int *));
90 void showhostmap_dead __P((natstat_t *));
91 void showhostmap_live __P((int, natstat_t *));
92 void dostats_dead __P((natstat_t *, int, int *));
93 int nat_matcharray __P((nat_t *, int *));
94
95 int opts;
96 int nohdrfields = 0;
97 wordtab_t *nat_fields = NULL;
98
99 void usage(name)
100 char *name;
101 {
102 fprintf(stderr, "Usage: %s [-CFhlnrRsv] [-f filename]\n", name);
103 exit(1);
104 }
105
106
107 int main(argc, argv)
108 int argc;
109 char *argv[];
110 {
111 int fd, c, mode, *natfilter;
112 char *file, *core, *kernel;
113 natstat_t ns, *nsp;
114 ipfobj_t obj;
115
116 fd = -1;
117 opts = 0;
118 nsp = &ns;
119 file = NULL;
120 core = NULL;
121 kernel = NULL;
122 mode = O_RDWR;
123 natfilter = NULL;
124
125 assigndefined(getenv("IPNAT_PREDEFINED"));
126
127 while ((c = getopt(argc, argv, "CdFf:hlm:M:N:nO:rRsv")) != -1)
128 switch (c)
129 {
130 case 'C' :
131 opts |= OPT_CLEAR;
132 break;
133 case 'd' :
134 opts |= OPT_DEBUG;
135 break;
136 case 'f' :
137 file = optarg;
138 break;
139 case 'F' :
140 opts |= OPT_FLUSH;
141 break;
142 case 'h' :
143 opts |=OPT_HITS;
144 break;
145 case 'l' :
146 opts |= OPT_LIST;
147 mode = O_RDONLY;
148 break;
149 case 'm' :
150 natfilter = parseipfexpr(optarg, NULL);
151 break;
152 case 'M' :
153 core = optarg;
154 break;
155 case 'N' :
156 kernel = optarg;
157 break;
158 case 'n' :
159 opts |= OPT_DONOTHING|OPT_DONTOPEN;
160 mode = O_RDONLY;
161 break;
162 case 'O' :
163 nat_fields = parsefields(natfields, optarg);
164 break;
165 case 'R' :
166 opts |= OPT_NORESOLVE;
167 break;
168 case 'r' :
169 opts |= OPT_REMOVE;
170 break;
171 case 's' :
172 opts |= OPT_STAT;
173 mode = O_RDONLY;
174 break;
175 case 'v' :
176 opts |= OPT_VERBOSE;
177 break;
178 default :
179 usage(argv[0]);
180 }
181
182 initparse();
183
184 if ((kernel != NULL) || (core != NULL)) {
185 (void) setgid(getgid());
186 (void) setuid(getuid());
187 }
188
189 if (!(opts & OPT_DONOTHING)) {
190 if (((fd = open(IPNAT_NAME, mode)) == -1) &&
191 ((fd = open(IPNAT_NAME, O_RDONLY)) == -1)) {
192 (void) fprintf(stderr, "%s: open: %s\n", IPNAT_NAME,
193 STRERROR(errno));
194 exit(1);
195 }
196 }
197
198 bzero((char *)&ns, sizeof(ns));
199
200 if ((opts & OPT_DONOTHING) == 0) {
201 if (checkrev(IPL_NAME) == -1) {
202 fprintf(stderr, "User/kernel version check failed\n");
203 exit(1);
204 }
205 }
206
207 if (!(opts & OPT_DONOTHING) && (kernel == NULL) && (core == NULL)) {
208 bzero((char *)&obj, sizeof(obj));
209 obj.ipfo_rev = IPFILTER_VERSION;
210 obj.ipfo_type = IPFOBJ_NATSTAT;
211 obj.ipfo_size = sizeof(*nsp);
212 obj.ipfo_ptr = (void *)nsp;
213 if (ioctl(fd, SIOCGNATS, &obj) == -1) {
214 ipferror(fd, "ioctl(SIOCGNATS)");
215 exit(1);
216 }
217 (void) setgid(getgid());
218 (void) setuid(getuid());
219 } else if ((kernel != NULL) || (core != NULL)) {
220 if (openkmem(kernel, core) == -1)
221 exit(1);
222
223 natstat_dead(nsp, kernel);
224 if (opts & (OPT_LIST|OPT_STAT))
225 dostats(fd, nsp, opts, 0, natfilter);
226 exit(0);
227 }
228
229 if (opts & (OPT_FLUSH|OPT_CLEAR))
230 flushtable(fd, opts, natfilter);
231 if (file) {
232 ipnat_parsefile(fd, ipnat_addrule, ioctl, file);
233 }
234 if (opts & (OPT_LIST|OPT_STAT))
235 dostats(fd, nsp, opts, 1, natfilter);
236 return 0;
237 }
238
239
240 /*
241 * Read NAT statistic information in using a symbol table and memory file
242 * rather than doing ioctl's.
243 */
244 void natstat_dead(nsp, kernel)
245 natstat_t *nsp;
246 char *kernel;
247 {
248 struct nlist nat_nlist[10] = {
249 { "nat_table" }, /* 0 */
250 { "nat_list" },
251 { "maptable" },
252 { "ipf_nattable_sz" },
253 { "ipf_natrules_sz" },
254 { "ipf_rdrrules_sz" }, /* 5 */
255 { "ipf_hostmap_sz" },
256 { "nat_instances" },
257 { NULL }
258 };
259 void *tables[2];
260
261 if (nlist(kernel, nat_nlist) == -1) {
262 fprintf(stderr, "nlist error\n");
263 return;
264 }
265
266 /*
267 * Normally the ioctl copies all of these values into the structure
268 * for us, before returning it to userland, so here we must copy each
269 * one in individually.
270 */
271 kmemcpy((char *)&tables, nat_nlist[0].n_value, sizeof(tables));
272 nsp->ns_side[0].ns_table = tables[0];
273 nsp->ns_side[1].ns_table = tables[1];
274
275 kmemcpy((char *)&nsp->ns_list, nat_nlist[1].n_value,
276 sizeof(nsp->ns_list));
277 kmemcpy((char *)&nsp->ns_maptable, nat_nlist[2].n_value,
278 sizeof(nsp->ns_maptable));
279 kmemcpy((char *)&nsp->ns_nattab_sz, nat_nlist[3].n_value,
280 sizeof(nsp->ns_nattab_sz));
281 kmemcpy((char *)&nsp->ns_rultab_sz, nat_nlist[4].n_value,
282 sizeof(nsp->ns_rultab_sz));
283 kmemcpy((char *)&nsp->ns_rdrtab_sz, nat_nlist[5].n_value,
284 sizeof(nsp->ns_rdrtab_sz));
285 kmemcpy((char *)&nsp->ns_hostmap_sz, nat_nlist[6].n_value,
286 sizeof(nsp->ns_hostmap_sz));
287 kmemcpy((char *)&nsp->ns_instances, nat_nlist[7].n_value,
288 sizeof(nsp->ns_instances));
289 }
290
291
292 /*
293 * Issue an ioctl to flush either the NAT rules table or the active mapping
294 * table or both.
295 */
296 void flushtable(fd, opts, match)
297 int fd, opts, *match;
298 {
299 int n = 0;
300
301 if (opts & OPT_FLUSH) {
302 n = 0;
303 if (!(opts & OPT_DONOTHING)) {
304 if (match != NULL) {
305 ipfobj_t obj;
306
307 obj.ipfo_rev = IPFILTER_VERSION;
308 obj.ipfo_size = match[0] * sizeof(int);
309 obj.ipfo_type = IPFOBJ_IPFEXPR;
310 obj.ipfo_ptr = match;
311 if (ioctl(fd, SIOCMATCHFLUSH, &obj) == -1) {
312 ipferror(fd, "ioctl(SIOCMATCHFLUSH)");
313 n = -1;
314 } else {
315 n = obj.ipfo_retval;
316 }
317 } else if (ioctl(fd, SIOCIPFFL, &n) == -1) {
318 ipferror(fd, "ioctl(SIOCIPFFL)");
319 n = -1;
320 }
321 }
322 if (n >= 0)
323 printf("%d entries flushed from NAT table\n", n);
324 }
325
326 if (opts & OPT_CLEAR) {
327 n = 1;
328 if (!(opts & OPT_DONOTHING) && ioctl(fd, SIOCIPFFL, &n) == -1)
329 ipferror(fd, "ioctl(SIOCCNATL)");
330 else
331 printf("%d entries flushed from NAT list\n", n);
332 }
333 }
334
335
336 /*
337 * Display NAT statistics.
338 */
339 void dostats_dead(nsp, opts, filter)
340 natstat_t *nsp;
341 int opts, *filter;
342 {
343 nat_t *np, nat;
344 ipnat_t ipn;
345 int i;
346
347 if (nat_fields == NULL) {
348 printf("List of active MAP/Redirect filters:\n");
349 while (nsp->ns_list) {
350 if (kmemcpy((char *)&ipn, (long)nsp->ns_list,
351 sizeof(ipn))) {
352 perror("kmemcpy");
353 break;
354 }
355 if (opts & OPT_HITS)
356 printf("%lu ", ipn.in_hits);
357 printnat(&ipn, opts & (OPT_DEBUG|OPT_VERBOSE));
358 nsp->ns_list = ipn.in_next;
359 }
360 }
361
362 if (nat_fields == NULL) {
363 printf("\nList of active sessions:\n");
364
365 } else if (nohdrfields == 0) {
366 for (i = 0; nat_fields[i].w_value != 0; i++) {
367 printfieldhdr(natfields, nat_fields + i);
368 if (nat_fields[i + 1].w_value != 0)
369 printf("\t");
370 }
371 printf("\n");
372 }
373
374 for (np = nsp->ns_instances; np; np = nat.nat_next) {
375 if (kmemcpy((char *)&nat, (long)np, sizeof(nat)))
376 break;
377 if ((filter != NULL) && (nat_matcharray(&nat, filter) == 0))
378 continue;
379 if (nat_fields != NULL) {
380 for (i = 0; nat_fields[i].w_value != 0; i++) {
381 printnatfield(&nat, nat_fields[i].w_value);
382 if (nat_fields[i + 1].w_value != 0)
383 printf("\t");
384 }
385 printf("\n");
386 } else {
387 printactivenat(&nat, opts, nsp->ns_ticks);
388 if (nat.nat_aps) {
389 int proto;
390
391 if (nat.nat_dir & NAT_OUTBOUND)
392 proto = nat.nat_pr[1];
393 else
394 proto = nat.nat_pr[0];
395 printaps(nat.nat_aps, opts, proto);
396 }
397 }
398 }
399
400 if (opts & OPT_VERBOSE)
401 showhostmap_dead(nsp);
402 }
403
404
405 void dotable(nsp, fd, alive, which, side)
406 natstat_t *nsp;
407 int fd, alive, which;
408 char *side;
409 {
410 int sz, i, used, maxlen, minlen, totallen;
411 ipftable_t table;
412 u_int *buckets;
413 ipfobj_t obj;
414
415 sz = sizeof(*buckets) * nsp->ns_nattab_sz;
416 buckets = (u_int *)malloc(sz);
417 if (buckets == NULL) {
418 fprintf(stderr,
419 "cannot allocate memory (%d) for buckets\n", sz);
420 return;
421 }
422
423 obj.ipfo_rev = IPFILTER_VERSION;
424 obj.ipfo_type = IPFOBJ_GTABLE;
425 obj.ipfo_size = sizeof(table);
426 obj.ipfo_ptr = &table;
427
428 if (which == 0) {
429 table.ita_type = IPFTABLE_BUCKETS_NATIN;
430 } else if (which == 1) {
431 table.ita_type = IPFTABLE_BUCKETS_NATOUT;
432 }
433 table.ita_table = buckets;
434
435 if (alive) {
436 if (ioctl(fd, SIOCGTABL, &obj) != 0) {
437 perror("SIOCFTABL");
438 free(buckets);
439 return;
440 }
441 } else {
442 if (kmemcpy((char *)buckets, (u_long)nsp->ns_nattab_sz, sz)) {
443 free(buckets);
444 return;
445 }
446 }
447
448 minlen = nsp->ns_side[which].ns_inuse;
449 totallen = 0;
450 maxlen = 0;
451 used = 0;
452
453 for (i = 0; i < nsp->ns_nattab_sz; i++) {
454 if (buckets[i] > maxlen)
455 maxlen = buckets[i];
456 if (buckets[i] < minlen)
457 minlen = buckets[i];
458 if (buckets[i] != 0)
459 used++;
460 totallen += buckets[i];
461 }
462
463 printf("%d%%\thash efficiency %s\n",
464 totallen ? used * 100 / totallen : 0, side);
465 printf("%2.2f%%\tbucket usage %s\n",
466 ((float)used / nsp->ns_nattab_sz) * 100.0, side);
467 printf("%d\tminimal length %s\n", minlen, side);
468 printf("%d\tmaximal length %s\n", maxlen, side);
469 printf("%.3f\taverage length %s\n",
470 used ? ((float)totallen / used) : 0.0, side);
471
472 free(buckets);
473 }
474
475
476 void dostats(fd, nsp, opts, alive, filter)
477 natstat_t *nsp;
478 int fd, opts, alive, *filter;
479 {
480 /*
481 * Show statistics ?
482 */
483 if (opts & OPT_STAT) {
484 printnatside("in", nsp, &nsp->ns_side[0]);
485 dotable(nsp, fd, alive, 0, "in");
486
487 printnatside("out", nsp, &nsp->ns_side[1]);
488 dotable(nsp, fd, alive, 1, "out");
489
490 printf("%lu\tlog successes\n", nsp->ns_side[0].ns_log);
491 printf("%lu\tlog failures\n", nsp->ns_side[1].ns_log);
492 printf("%lu\tadded in\n%lu\tadded out\n",
493 nsp->ns_side[0].ns_added,
494 nsp->ns_side[1].ns_added);
495 printf("%lu\texpired\n", nsp->ns_expire);
496 printf("%u\twilds\n", nsp->ns_wilds);
497 if (opts & OPT_VERBOSE)
498 printf("list %p\n", nsp->ns_list);
499 }
500
501 if (opts & OPT_LIST) {
502 if (alive)
503 dostats_live(fd, nsp, opts, filter);
504 else
505 dostats_dead(nsp, opts, filter);
506 }
507 }
508
509
510 /*
511 * Display NAT statistics.
512 */
513 void dostats_live(fd, nsp, opts, filter)
514 natstat_t *nsp;
515 int fd, opts, *filter;
516 {
517 ipfgeniter_t iter;
518 char buffer[2000];
519 ipfobj_t obj;
520 ipnat_t *ipn;
521 nat_t nat;
522 int i;
523
524 bzero((char *)&obj, sizeof(obj));
525 obj.ipfo_rev = IPFILTER_VERSION;
526 obj.ipfo_type = IPFOBJ_GENITER;
527 obj.ipfo_size = sizeof(iter);
528 obj.ipfo_ptr = &iter;
529
530 iter.igi_type = IPFGENITER_IPNAT;
531 iter.igi_nitems = 1;
532 iter.igi_data = buffer;
533 ipn = (ipnat_t *)buffer;
534
535 /*
536 * Show list of NAT rules and NAT sessions ?
537 */
538 if (nat_fields == NULL) {
539 printf("List of active MAP/Redirect filters:\n");
540 while (nsp->ns_list) {
541 if (ioctl(fd, SIOCGENITER, &obj) == -1)
542 break;
543 if (opts & OPT_HITS)
544 printf("%lu ", ipn->in_hits);
545 printnat(ipn, opts & (OPT_DEBUG|OPT_VERBOSE));
546 nsp->ns_list = ipn->in_next;
547 }
548 }
549
550 if (nat_fields == NULL) {
551 printf("\nList of active sessions:\n");
552
553 } else if (nohdrfields == 0) {
554 for (i = 0; nat_fields[i].w_value != 0; i++) {
555 printfieldhdr(natfields, nat_fields + i);
556 if (nat_fields[i + 1].w_value != 0)
557 printf("\t");
558 }
559 printf("\n");
560 }
561
562 i = IPFGENITER_IPNAT;
563 (void) ioctl(fd,SIOCIPFDELTOK, &i);
564
565
566 iter.igi_type = IPFGENITER_NAT;
567 iter.igi_nitems = 1;
568 iter.igi_data = &nat;
569
570 while (nsp->ns_instances != NULL) {
571 if (ioctl(fd, SIOCGENITER, &obj) == -1)
572 break;
573 if ((filter != NULL) && (nat_matcharray(&nat, filter) == 0))
574 continue;
575 if (nat_fields != NULL) {
576 for (i = 0; nat_fields[i].w_value != 0; i++) {
577 printnatfield(&nat, nat_fields[i].w_value);
578 if (nat_fields[i + 1].w_value != 0)
579 printf("\t");
580 }
581 printf("\n");
582 } else {
583 printactivenat(&nat, opts, nsp->ns_ticks);
584 if (nat.nat_aps) {
585 int proto;
586
587 if (nat.nat_dir & NAT_OUTBOUND)
588 proto = nat.nat_pr[1];
589 else
590 proto = nat.nat_pr[0];
591 printaps(nat.nat_aps, opts, proto);
592 }
593 }
594 nsp->ns_instances = nat.nat_next;
595 }
596
597 if (opts & OPT_VERBOSE)
598 showhostmap_live(fd, nsp);
599
600 i = IPFGENITER_NAT;
601 (void) ioctl(fd,SIOCIPFDELTOK, &i);
602 }
603
604
605 /*
606 * Display the active host mapping table.
607 */
608 void showhostmap_dead(nsp)
609 natstat_t *nsp;
610 {
611 hostmap_t hm, *hmp, **maptable;
612 u_int hv;
613
614 printf("\nList of active host mappings:\n");
615
616 maptable = (hostmap_t **)malloc(sizeof(hostmap_t *) *
617 nsp->ns_hostmap_sz);
618 if (kmemcpy((char *)maptable, (u_long)nsp->ns_maptable,
619 sizeof(hostmap_t *) * nsp->ns_hostmap_sz)) {
620 perror("kmemcpy (maptable)");
621 return;
622 }
623
624 for (hv = 0; hv < nsp->ns_hostmap_sz; hv++) {
625 hmp = maptable[hv];
626
627 while (hmp) {
628 if (kmemcpy((char *)&hm, (u_long)hmp, sizeof(hm))) {
629 perror("kmemcpy (hostmap)");
630 return;
631 }
632
633 printhostmap(&hm, hv);
634 hmp = hm.hm_next;
635 }
636 }
637 free(maptable);
638 }
639
640
641 /*
642 * Display the active host mapping table.
643 */
644 void showhostmap_live(fd, nsp)
645 int fd;
646 natstat_t *nsp;
647 {
648 ipfgeniter_t iter;
649 hostmap_t hm;
650 ipfobj_t obj;
651 int i;
652
653 bzero((char *)&obj, sizeof(obj));
654 obj.ipfo_rev = IPFILTER_VERSION;
655 obj.ipfo_type = IPFOBJ_GENITER;
656 obj.ipfo_size = sizeof(iter);
657 obj.ipfo_ptr = &iter;
658
659 iter.igi_type = IPFGENITER_HOSTMAP;
660 iter.igi_nitems = 1;
661 iter.igi_data = &hm;
662
663 printf("\nList of active host mappings:\n");
664
665 while (nsp->ns_maplist != NULL) {
666 if (ioctl(fd, SIOCGENITER, &obj) == -1)
667 break;
668 printhostmap(&hm, hm.hm_hv);
669 nsp->ns_maplist = hm.hm_next;
670 }
671
672 i = IPFGENITER_HOSTMAP;
673 (void) ioctl(fd,SIOCIPFDELTOK, &i);
674 }
675
676
677 int nat_matcharray(nat, array)
678 nat_t *nat;
679 int *array;
680 {
681 int i, n, *x, e, p;
682
683 e = 0;
684 n = array[0];
685 x = array + 1;
686
687 for (; n > 0; x += 3 + x[3]) {
688 if (x[0] == IPF_EXP_END)
689 break;
690 e = 0;
691
692 n -= x[3] + 3;
693
694 p = x[0] >> 16;
695 if (p != 0 && p != nat->nat_pr[1])
696 break;
697
698 switch (x[0])
699 {
700 case IPF_EXP_IP_PR :
701 for (i = 0; !e && i < x[3]; i++) {
702 e |= (nat->nat_pr[1] == x[i + 3]);
703 }
704 break;
705
706 case IPF_EXP_IP_SRCADDR :
707 for (i = 0; !e && i < x[3]; i++) {
708 e |= ((nat->nat_nsrcaddr & x[i + 4]) ==
709 x[i + 3]);
710 }
711 break;
712
713 case IPF_EXP_IP_DSTADDR :
714 for (i = 0; !e && i < x[3]; i++) {
715 e |= ((nat->nat_ndstaddr & x[i + 4]) ==
716 x[i + 3]);
717 }
718 break;
719
720 case IPF_EXP_IP_ADDR :
721 for (i = 0; !e && i < x[3]; i++) {
722 e |= ((nat->nat_nsrcaddr & x[i + 4]) ==
723 x[i + 3]) ||
724 ((nat->nat_ndstaddr & x[i + 4]) ==
725 x[i + 3]);
726 }
727 break;
728
729 case IPF_EXP_UDP_PORT :
730 case IPF_EXP_TCP_PORT :
731 for (i = 0; !e && i < x[3]; i++) {
732 e |= (nat->nat_nsport == x[i + 3]) ||
733 (nat->nat_ndport == x[i + 3]);
734 }
735 break;
736
737 case IPF_EXP_UDP_SPORT :
738 case IPF_EXP_TCP_SPORT :
739 for (i = 0; !e && i < x[3]; i++) {
740 e |= (nat->nat_nsport == x[i + 3]);
741 }
742 break;
743
744 case IPF_EXP_UDP_DPORT :
745 case IPF_EXP_TCP_DPORT :
746 for (i = 0; !e && i < x[3]; i++) {
747 e |= (nat->nat_ndport == x[i + 3]);
748 }
749 break;
750 }
751 e ^= x[2];
752
753 if (!e)
754 break;
755 }
756
757 return e;
758 }
759