]> git.saurik.com Git - apple/network_cmds.git/blob - natd.tproj/natd.c
network_cmds-511.50.3.tar.gz
[apple/network_cmds.git] / natd.tproj / natd.c
1 /*
2 * Copyright (c) 2000-2009 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 /*
30 * natd - Network Address Translation Daemon for FreeBSD.
31 *
32 * This software is provided free of charge, with no
33 * warranty of any kind, either expressed or implied.
34 * Use at your own risk.
35 *
36 * You may copy, modify and distribute this software (natd.c) freely.
37 *
38 * Ari Suutari <suutari@iki.fi>
39 *
40 * Based upon:
41 * $FreeBSD: src/sbin/natd/natd.c,v 1.25.2.3 2000/07/11 20:00:57 ru Exp $
42 */
43
44 #define SYSLOG_NAMES
45
46 #include <sys/types.h>
47 #include <sys/socket.h>
48 #include <net/if.h>
49 #include <ifaddrs.h>
50 #include <sys/sysctl.h>
51 #include <sys/time.h>
52
53 #include <netinet/in.h>
54 #include <netinet/in_systm.h>
55 #include <netinet/ip.h>
56 #include <netinet/tcp.h>
57 #include <netinet/udp.h>
58 #include <netinet/ip_icmp.h>
59 #include <net/if.h>
60 #include <net/if_dl.h>
61 #include <net/route.h>
62 #include <arpa/inet.h>
63
64 #include <alias.h>
65 void DumpInfo(void);
66
67 #include <ctype.h>
68 #include <err.h>
69 #include <errno.h>
70 #include <netdb.h>
71 #include <signal.h>
72 #include <stdio.h>
73 #include <stdlib.h>
74 #include <string.h>
75 #include <syslog.h>
76 #include <unistd.h>
77 #include <fcntl.h>
78 #include <mach/mach_time.h>
79 #include <mach/clock_types.h>
80
81 #include "natd.h"
82
83 /*
84 * Default values for input and output
85 * divert socket ports.
86 */
87
88 #define DEFAULT_SERVICE "natd"
89
90 /*
91 * Definition of a port range, and macros to deal with values.
92 * FORMAT: HI 16-bits == first port in range, 0 == all ports.
93 * LO 16-bits == number of ports in range
94 * NOTES: - Port values are not stored in network byte order.
95 */
96
97 typedef uint32_t port_range;
98
99 #define GETLOPORT(x) ((x) >> 0x10)
100 #define GETNUMPORTS(x) ((x) & 0x0000ffff)
101 #define GETHIPORT(x) (GETLOPORT((x)) + GETNUMPORTS((x)))
102
103 /* Set y to be the low-port value in port_range variable x. */
104 #define SETLOPORT(x,y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
105
106 /* Set y to be the number of ports in port_range variable x. */
107 #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y))
108
109 /*
110 * Function prototypes.
111 */
112
113 static void DoAliasing (int fd, int direction);
114 static void DaemonMode (void);
115 static void HandleRoutingInfo (int fd);
116 static void Usage (void);
117 static char* FormatPacket (struct ip*);
118 static void PrintPacket (struct ip*);
119 static void SyslogPacket (struct ip*, int priority, const char *label);
120 static void SetAliasAddressFromIfName (const char *ifName);
121 static void InitiateShutdown (int);
122 static void Shutdown (int);
123 static void RefreshAddr (int);
124 static void HandleInfo (int);
125 static void ParseOption (const char* option, const char* parms);
126 static void ReadConfigFile (const char* fileName);
127 static void SetupPortRedirect (const char* parms);
128 static void SetupProtoRedirect(const char* parms);
129 static void SetupAddressRedirect (const char* parms);
130 static void StrToAddr (const char* str, struct in_addr* addr);
131 static u_short StrToPort (const char* str, const char* proto);
132 static int StrToPortRange (const char* str, const char* proto, port_range *portRange);
133 static int StrToProto (const char* str);
134 static int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange);
135 static void ParseArgs (int argc, char** argv);
136 static void FlushPacketBuffer (int fd);
137 static void DiscardIncomingPackets (int fd);
138 static void SetupPunchFW(const char *strValue);
139
140 /*
141 * Globals.
142 */
143
144 static int verbose;
145 static int background;
146 static int running;
147 static int assignAliasAddr;
148 static char* ifName;
149 static int ifIndex;
150 static u_short inPort;
151 static u_short outPort;
152 static u_short inOutPort;
153 static struct in_addr aliasAddr;
154 static int dynamicMode;
155 static int clampMSS;
156 static int ifMTU;
157 static int aliasOverhead;
158 static int icmpSock;
159 static char packetBuf[IP_MAXPACKET];
160 static int packetLen;
161 static struct sockaddr_in packetAddr;
162 static int packetSock;
163 static int packetDirection;
164 static int dropIgnoredIncoming;
165 static int logDropped;
166 static int logFacility;
167 static int dumpinfo;
168
169 #define NATPORTMAP 1
170
171 #ifdef NATPORTMAP
172
173 /*
174 * Note: more details on NAT-PMP can be found at :
175 * <http://files.dns-sd.org/draft-cheshire-nat-pmp.txt>
176 */
177
178 #define NATPMP_ANNOUNCEMENT_PORT 5350
179 #define NATPMP_PORT 5351
180
181 #define NATPMVERSION 0
182 #define PUBLICADDRREQ 0
183 #define MAPUDPREQ 1
184 #define MAPTCPREQ 2
185 #define MAPUDPTCPREQ 3
186 #define SERVERREPLYOP 128
187
188 #define SUCCESS 0
189 #define NOTSUPPORTEDVERSION 1
190 #define NOTAUTHORIZED 2
191 #define NETWORKFAILURE 3
192 #define OUTOFRESOURCES 4
193 #define UNSUPPORTEDOPCODE 5
194
195 #define MAXRETRY 10
196 #define TIMER_RATE 250000
197
198 #define FAILED -1
199
200 typedef struct stdportmaprequest {
201 uint8_t version;
202 uint8_t opcode;
203 } stdportmaprequest;
204
205 typedef struct publicportreq {
206 uint8_t version;
207 uint8_t opcode;
208 uint16_t reserved;
209 uint16_t privateport;
210 uint16_t publicport;
211 uint32_t lifetime; /* in seconds */
212 } publicportreq;
213
214 typedef struct publicaddrreply {
215 uint8_t version;
216 uint8_t opcode;
217 uint16_t result;
218 uint32_t epoch;
219 struct in_addr addr;
220 } publicaddrreply;
221
222 typedef struct publicportreply {
223 uint8_t version;
224 uint8_t opcode;
225 uint16_t result;
226 uint32_t epoch;
227 uint16_t privateport;
228 uint16_t publicport;
229 uint32_t lifetime; /* in seconds */
230 } publicportreply;
231
232 typedef struct stderrreply {
233 uint8_t version;
234 uint8_t opcode;
235 uint16_t result;
236 uint32_t epoch;
237 } stderrreply;
238
239
240 static int enable_natportmap = 0;
241 static struct in_addr lastassignaliasAddr;
242 static int portmapSock = -1;
243 static struct in_addr *forwardedinterfaceaddr;
244 static char **forwardedinterfacename;
245 static int numofinterfaces = 0; /* has to be at least one */
246 static int numoftries=MAXRETRY;
247 static struct itimerval itval;
248 static int Natdtimerset = 0;
249 static double secdivisor;
250
251
252 static void HandlePortMap( int fd );
253 static void SendPortMapResponse( int fd, struct sockaddr_in *clientaddr, int clientaddrlen, unsigned char origopcode, unsigned short result);
254 static void SendPublicAddress( int fd, struct sockaddr_in *clientaddr, int clientaddrlen );
255 static void SendPublicPortResponse( int fd, struct sockaddr_in *clientaddr, int clientaddrlen, publicportreq *reply, u_short publicport, int result);
256 static void Doubletime( struct timeval *tvp);
257 static void Stoptimer();
258 static void Natdtimer();
259 static void SendPortMapMulti( );
260 static void NotifyPublicAddress();
261 static void DoPortMapping( int fd, struct sockaddr_in *clientaddr, int clientaddrlen, publicportreq *req);
262 static void NatPortMapPInit();
263
264 extern int FindAliasPortOut(struct in_addr src_addr, struct in_addr dst_addr, u_short src_port, u_short pub_port, u_char proto, int lifetime, char addmapping);
265
266 #endif /* NATPORTMAP */
267
268 int main (int argc, char** argv)
269 {
270 int divertIn;
271 int divertOut;
272 int divertInOut;
273 int routeSock;
274 struct sockaddr_in addr;
275 fd_set readMask;
276 fd_set writeMask;
277 int fdMax;
278 int fdFlags;
279 /*
280 * Initialize packet aliasing software.
281 * Done already here to be able to alter option bits
282 * during command line and configuration file processing.
283 */
284 PacketAliasInit ();
285 /*
286 * Parse options.
287 */
288 inPort = 0;
289 outPort = 0;
290 verbose = 0;
291 inOutPort = 0;
292 ifName = NULL;
293 ifMTU = -1;
294 background = 0;
295 running = 1;
296 assignAliasAddr = 0;
297 aliasAddr.s_addr = INADDR_NONE;
298 #ifdef NATPORTMAP
299 lastassignaliasAddr.s_addr = INADDR_NONE;
300 #endif
301 aliasOverhead = 12;
302 dynamicMode = 0;
303 logDropped = 0;
304 logFacility = LOG_DAEMON;
305 /*
306 * Mark packet buffer empty.
307 */
308 packetSock = -1;
309 packetDirection = DONT_KNOW;
310
311 ParseArgs (argc, argv);
312 /*
313 * Open syslog channel.
314 */
315 openlog ("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0),
316 logFacility);
317 /*
318 * Check that valid aliasing address has been given.
319 */
320 if (aliasAddr.s_addr == INADDR_NONE && ifName == NULL)
321 errx (1, "aliasing address not given");
322
323 /*
324 * Check that valid port number is known.
325 */
326 if (inPort != 0 || outPort != 0)
327 if (inPort == 0 || outPort == 0)
328 errx (1, "both input and output ports are required");
329
330 if (inPort == 0 && outPort == 0 && inOutPort == 0)
331 ParseOption ("port", DEFAULT_SERVICE);
332
333 /*
334 * Check if ignored packets should be dropped.
335 */
336 dropIgnoredIncoming = PacketAliasSetMode (0, 0);
337 dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING;
338 /*
339 * Create divert sockets. Use only one socket if -p was specified
340 * on command line. Otherwise, create separate sockets for
341 * outgoing and incoming connnections.
342 */
343 if (inOutPort) {
344
345 divertInOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
346 if (divertInOut == -1)
347 Quit ("Unable to create divert socket.");
348
349 divertIn = -1;
350 divertOut = -1;
351 /*
352 * Bind socket.
353 */
354
355 addr.sin_family = AF_INET;
356 addr.sin_addr.s_addr = INADDR_ANY;
357 addr.sin_port = inOutPort;
358
359 if (bind (divertInOut,
360 (struct sockaddr*) &addr,
361 sizeof addr) == -1)
362 Quit ("Unable to bind divert socket.");
363 }
364 else {
365
366 divertIn = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
367 if (divertIn == -1)
368 Quit ("Unable to create incoming divert socket.");
369
370 divertOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
371 if (divertOut == -1)
372 Quit ("Unable to create outgoing divert socket.");
373
374 divertInOut = -1;
375
376 /*
377 * Bind divert sockets.
378 */
379
380 addr.sin_family = AF_INET;
381 addr.sin_addr.s_addr = INADDR_ANY;
382 addr.sin_port = inPort;
383
384 if (bind (divertIn,
385 (struct sockaddr*) &addr,
386 sizeof addr) == -1)
387 Quit ("Unable to bind incoming divert socket.");
388
389 addr.sin_family = AF_INET;
390 addr.sin_addr.s_addr = INADDR_ANY;
391 addr.sin_port = outPort;
392
393 if (bind (divertOut,
394 (struct sockaddr*) &addr,
395 sizeof addr) == -1)
396 Quit ("Unable to bind outgoing divert socket.");
397 }
398 /*
399 * Create routing socket if interface name specified and in dynamic mode.
400 */
401 routeSock = -1;
402 if (ifName) {
403 if (dynamicMode) {
404
405 routeSock = socket (PF_ROUTE, SOCK_RAW, 0);
406 if (routeSock == -1)
407 Quit ("Unable to create routing info socket.");
408
409 assignAliasAddr = 1;
410 }
411 else{
412 SetAliasAddressFromIfName (ifName);
413 }
414 }
415 /*
416 * Create socket for sending ICMP messages.
417 */
418 icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
419 if (icmpSock == -1)
420 Quit ("Unable to create ICMP socket.");
421
422 if ((fdFlags = fcntl(icmpSock, F_GETFL, 0)) == -1)
423 Quit ("fcntl F_GETFL ICMP socket.");
424 fdFlags |= O_NONBLOCK;
425 if (fcntl(icmpSock, F_SETFL, fdFlags) == -1)
426 Quit ("fcntl F_SETFL ICMP socket.");
427
428 #if NATPORTMAP
429 if ( enable_natportmap )
430 {
431 /* create socket to listen for port mapping */
432 portmapSock = socket( AF_INET, SOCK_DGRAM, 0);
433 if ( portmapSock != -1 )
434 {
435 addr.sin_family = AF_INET;
436 addr.sin_addr.s_addr = INADDR_ANY;
437 addr.sin_port = htons(NATPMP_PORT);
438
439 if (bind ( portmapSock,
440 (struct sockaddr*) &addr,
441 sizeof addr) == -1)
442 printf("Binding to NATPM port failed!\n");
443
444 /* NATPORTMAPP initial set up */
445 NatPortMapPInit();
446 }
447 if ( !Natdtimerset ){
448 Natdtimerset = 1;
449 signal(SIGALRM, Natdtimer);
450 }
451 }
452 #endif /* NATPORTMAP */
453
454 /*
455 * Become a daemon unless verbose mode was requested.
456 */
457 if (!verbose)
458 DaemonMode ();
459 /*
460 * Catch signals to manage shutdown and
461 * refresh of interface address.
462 */
463 siginterrupt(SIGTERM, 1);
464 siginterrupt(SIGHUP, 1);
465 signal (SIGTERM, InitiateShutdown);
466 signal (SIGHUP, RefreshAddr);
467 signal (SIGINFO, HandleInfo);
468 /*
469 * Set alias address if it has been given.
470 */
471 if (aliasAddr.s_addr != INADDR_NONE)
472 {
473 PacketAliasSetAddress (aliasAddr);
474 #ifdef NATPORTMAP
475 if ( (enable_natportmap) && (aliasAddr.s_addr != lastassignaliasAddr.s_addr) ){
476 lastassignaliasAddr.s_addr = aliasAddr.s_addr;
477 NotifyPublicAddress();
478 }
479 #endif
480 }
481 /*
482 * We need largest descriptor number for select.
483 */
484
485 fdMax = -1;
486
487 if (divertIn > fdMax)
488 fdMax = divertIn;
489
490 if (divertOut > fdMax)
491 fdMax = divertOut;
492
493 if (divertInOut > fdMax)
494 fdMax = divertInOut;
495
496 if (routeSock > fdMax)
497 fdMax = routeSock;
498
499 if (icmpSock > fdMax)
500 fdMax = icmpSock;
501
502 #ifdef NATPORTMAP
503 if ( portmapSock > fdMax )
504 fdMax = portmapSock;
505
506 #endif
507
508 while (running) {
509
510 if (divertInOut != -1 && !ifName && packetSock == -1) {
511 /*
512 * When using only one socket, just call
513 * DoAliasing repeatedly to process packets.
514 */
515 DoAliasing (divertInOut, DONT_KNOW);
516 continue;
517 }
518 /*
519 * Build read mask from socket descriptors to select.
520 */
521 FD_ZERO (&readMask);
522 FD_ZERO (&writeMask);
523
524 /*
525 * If there is unsent packet in buffer, use select
526 * to check when socket comes writable again.
527 */
528 if (packetSock != -1) {
529
530 FD_SET (packetSock, &writeMask);
531 }
532 else {
533 /*
534 * No unsent packet exists - safe to check if
535 * new ones are available.
536 */
537 if (divertIn != -1)
538 FD_SET (divertIn, &readMask);
539
540 if (divertOut != -1)
541 FD_SET (divertOut, &readMask);
542
543 if (divertInOut != -1)
544 FD_SET (divertInOut, &readMask);
545
546 if (icmpSock != -1)
547 FD_SET(icmpSock, &readMask);
548 }
549 /*
550 * Routing info is processed always.
551 */
552 if (routeSock != -1)
553 FD_SET (routeSock, &readMask);
554 #ifdef NATPORTMAP
555 if ( portmapSock != -1 )
556 FD_SET (portmapSock, &readMask);
557 #endif
558 if (select (fdMax + 1,
559 &readMask,
560 &writeMask,
561 NULL,
562 NULL) == -1) {
563
564 if (errno == EINTR) {
565 if (dumpinfo) {
566 DumpInfo();
567 dumpinfo = 0;
568 }
569 continue;
570 }
571 Quit ("Select failed.");
572 }
573
574 if (packetSock != -1)
575 if (FD_ISSET (packetSock, &writeMask))
576 FlushPacketBuffer (packetSock);
577
578 if (divertIn != -1)
579 if (FD_ISSET (divertIn, &readMask))
580 DoAliasing (divertIn, INPUT);
581
582 if (divertOut != -1)
583 if (FD_ISSET (divertOut, &readMask))
584 DoAliasing (divertOut, OUTPUT);
585
586 if (divertInOut != -1)
587 if (FD_ISSET (divertInOut, &readMask))
588 DoAliasing (divertInOut, DONT_KNOW);
589
590 if (routeSock != -1)
591 if (FD_ISSET (routeSock, &readMask))
592 HandleRoutingInfo (routeSock);
593
594 if (icmpSock != -1)
595 if (FD_ISSET (icmpSock, &readMask))
596 DiscardIncomingPackets (icmpSock);
597
598 #ifdef NATPORTMAP
599 if ( portmapSock != -1)
600 if (FD_ISSET (portmapSock, &readMask))
601 HandlePortMap( portmapSock );
602 #endif
603 }
604
605 if (background)
606 unlink (PIDFILE);
607
608 return 0;
609 }
610
611 static void DaemonMode ()
612 {
613 FILE* pidFile;
614
615 daemon (0, 0);
616 background = 1;
617
618 pidFile = fopen (PIDFILE, "w");
619 if (pidFile) {
620
621 fprintf (pidFile, "%d\n", getpid ());
622 fclose (pidFile);
623 }
624
625 #ifdef DEBUG
626 #include <fcntl.h>
627 {
628 int fd;
629
630 fd = open("/var/run/natd.log", O_WRONLY|O_CREAT|O_TRUNC, 0644);
631 if (fd >= 0) {
632 if (fd != STDOUT_FILENO) {
633 dup2(fd, STDOUT_FILENO);
634 close(fd);
635 }
636 dup2(STDOUT_FILENO, STDERR_FILENO);
637 }
638 }
639 #endif
640 }
641
642 static void ParseArgs (int argc, char** argv)
643 {
644 int arg;
645 char* opt;
646 char parmBuf[256];
647 int len; /* bounds checking */
648
649 for (arg = 1; arg < argc; arg++) {
650
651 opt = argv[arg];
652 if (*opt != '-') {
653
654 warnx ("invalid option %s", opt);
655 Usage ();
656 }
657
658 parmBuf[0] = '\0';
659 len = 0;
660
661 while (arg < argc - 1) {
662
663 if (argv[arg + 1][0] == '-')
664 break;
665
666 if (len) {
667 strncat (parmBuf, " ", sizeof(parmBuf) - (len + 1));
668 len += strlen(parmBuf + len);
669 }
670
671 ++arg;
672 strncat (parmBuf, argv[arg], sizeof(parmBuf) - (len + 1));
673 len += strlen(parmBuf + len);
674
675 }
676
677 ParseOption (opt + 1, (len ? parmBuf : NULL));
678
679 }
680 }
681
682 static void DoAliasing (int fd, int direction)
683 {
684 int bytes;
685 int origBytes;
686 int status;
687 socklen_t addrSize;
688 struct ip* ip;
689
690 if (assignAliasAddr) {
691
692 SetAliasAddressFromIfName (ifName);
693 assignAliasAddr = 0;
694 }
695 /*
696 * Get packet from socket.
697 */
698 addrSize = sizeof packetAddr;
699 origBytes = recvfrom (fd,
700 packetBuf,
701 sizeof packetBuf,
702 0,
703 (struct sockaddr*) &packetAddr,
704 &addrSize);
705
706 if (origBytes == -1) {
707
708 if (errno != EINTR)
709 Warn ("read from divert socket failed");
710
711 return;
712 }
713 /*
714 * This is a IP packet.
715 */
716 ip = (struct ip*) packetBuf;
717 if (direction == DONT_KNOW) {
718 if (packetAddr.sin_addr.s_addr == INADDR_ANY)
719 direction = OUTPUT;
720 else
721 direction = INPUT;
722 }
723
724 if (verbose) {
725 /*
726 * Print packet direction and protocol type.
727 */
728 printf (direction == OUTPUT ? "Out " : "In ");
729
730 switch (ip->ip_p) {
731 case IPPROTO_TCP:
732 printf ("[TCP] ");
733 break;
734
735 case IPPROTO_UDP:
736 printf ("[UDP] ");
737 break;
738
739 case IPPROTO_ICMP:
740 printf ("[ICMP] ");
741 break;
742
743 default:
744 printf ("[%d] ", ip->ip_p);
745 break;
746 }
747 /*
748 * Print addresses.
749 */
750 PrintPacket (ip);
751 }
752
753 if (direction == OUTPUT) {
754 /*
755 * Outgoing packets. Do aliasing.
756 */
757 PacketAliasOut (packetBuf, IP_MAXPACKET);
758 }
759 else {
760
761 /*
762 * Do aliasing.
763 */
764 status = PacketAliasIn (packetBuf, IP_MAXPACKET);
765 if (status == PKT_ALIAS_IGNORED &&
766 dropIgnoredIncoming) {
767
768 if (verbose)
769 printf (" dropped.\n");
770
771 if (logDropped)
772 SyslogPacket (ip, LOG_WARNING, "denied");
773
774 return;
775 }
776 }
777 /*
778 * Length might have changed during aliasing.
779 */
780 bytes = ntohs (ip->ip_len);
781 /*
782 * Update alias overhead size for outgoing packets.
783 */
784 if (direction == OUTPUT &&
785 bytes - origBytes > aliasOverhead)
786 aliasOverhead = bytes - origBytes;
787
788 if (verbose) {
789
790 /*
791 * Print addresses after aliasing.
792 */
793 printf (" aliased to\n");
794 printf (" ");
795 PrintPacket (ip);
796 printf ("\n");
797 }
798
799 packetLen = bytes;
800 packetSock = fd;
801 packetDirection = direction;
802
803 FlushPacketBuffer (fd);
804 }
805
806 static void FlushPacketBuffer (int fd)
807 {
808 int wrote;
809 char msgBuf[80];
810 /*
811 * Put packet back for processing.
812 */
813 wrote = sendto (fd,
814 packetBuf,
815 packetLen,
816 0,
817 (struct sockaddr*) &packetAddr,
818 sizeof packetAddr);
819
820 if (wrote != packetLen) {
821 /*
822 * If buffer space is not available,
823 * just return. Main loop will take care of
824 * retrying send when space becomes available.
825 */
826 if (errno == ENOBUFS)
827 return;
828
829 if (errno == EMSGSIZE) {
830
831 if (packetDirection == OUTPUT &&
832 ifMTU != -1)
833 SendNeedFragIcmp (icmpSock,
834 (struct ip*) packetBuf,
835 ifMTU - aliasOverhead);
836 }
837 else {
838
839 snprintf (msgBuf, sizeof(msgBuf), "failed to write packet back");
840 Warn (msgBuf);
841 }
842 }
843
844 packetSock = -1;
845 }
846
847 static void HandleRoutingInfo (int fd)
848 {
849 int bytes;
850 struct if_msghdr ifMsg;
851 /*
852 * Get packet from socket.
853 */
854 bytes = read (fd, &ifMsg, sizeof ifMsg);
855 if (bytes == -1) {
856
857 Warn ("read from routing socket failed");
858 return;
859 }
860
861 if (ifMsg.ifm_version != RTM_VERSION) {
862
863 Warn ("unexpected packet read from routing socket");
864 return;
865 }
866
867 if (verbose)
868 printf ("Routing message %#x received.\n", ifMsg.ifm_type);
869
870 if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO) &&
871 ifMsg.ifm_index == ifIndex) {
872 if (verbose)
873 printf("Interface address/MTU has probably changed.\n");
874 assignAliasAddr = 1;
875 }
876 }
877
878 static void DiscardIncomingPackets (int fd)
879 {
880 struct sockaddr_in sin;
881 char buffer[80];
882 socklen_t slen = sizeof(sin);
883
884 while (recvfrom(fd, buffer, sizeof(buffer), 0, (struct sockaddr *)&sin, &slen) != -1) {
885 ;
886 }
887 }
888
889 #ifdef NATPORTMAP
890
891 void getdivisor()
892 {
893 struct mach_timebase_info info;
894
895 (void) mach_timebase_info (&info);
896
897 secdivisor = ( (double)info.denom / (double)info.numer) * 1000;
898
899 }
900
901 uint32_t getuptime()
902 {
903 uint64_t now;
904 uint32_t epochtime;
905
906 now = mach_absolute_time();
907 epochtime = (now / secdivisor) / USEC_PER_SEC;
908 return ( epochtime );
909
910 }
911
912 /* set up neccessary info for doing NatPortMapP */
913 static void NatPortMapPInit()
914 {
915 int i;
916 struct ifaddrs *ifap, *ifa;
917
918 forwardedinterfaceaddr = (struct in_addr *)
919 malloc(numofinterfaces * sizeof(*forwardedinterfaceaddr));
920 bzero(forwardedinterfaceaddr,
921 numofinterfaces * sizeof(*forwardedinterfaceaddr));
922 /* interface address hasn't been set up, get interface address */
923
924 if (getifaddrs(&ifap) == -1)
925 Quit ("getifaddrs failed.");
926
927 for ( ifa= ifap; ifa; ifa=ifa->ifa_next)
928 {
929 struct sockaddr_in * a;
930 if (ifa->ifa_addr->sa_family != AF_INET)
931 {
932 continue;
933 }
934 a = (struct sockaddr_in *)ifa->ifa_addr;
935 for ( i = 0; i < numofinterfaces; i++ )
936 {
937 if (strcmp(ifa->ifa_name, forwardedinterfacename[i]))
938 {
939 continue;
940 }
941 if (forwardedinterfaceaddr[i].s_addr == 0)
942 {
943 /* copy the first IP address */
944 forwardedinterfaceaddr[i] = a->sin_addr;
945 }
946 break;
947 }
948 }
949 freeifaddrs( ifap );
950 getdivisor();
951 }
952
953 /* SendPortMapResponse */
954 /* send generic reponses to NATPORTMAP requests */
955 static void SendPortMapResponse( int fd, struct sockaddr_in *clientaddr, int clientaddrlen, unsigned char origopcode, unsigned short result)
956 {
957 stderrreply reply;
958 int bytes;
959
960 reply.version = NATPMVERSION;
961 reply.opcode = origopcode + SERVERREPLYOP;
962 reply.result = htons(result);
963 reply.epoch = htonl(getuptime());
964 bytes = sendto( fd, (void*)&reply, sizeof(reply), 0, (struct sockaddr*)clientaddr, clientaddrlen );
965 if ( bytes != sizeof(reply) )
966 printf( "PORTMAP::problem sending portmap reply - opcode %d\n", reply.opcode );
967 }
968
969 /* SendPublicAddress */
970 /* return public address to requestor */
971 static void SendPublicAddress( int fd, struct sockaddr_in *clientaddr, int clientaddrlen )
972 {
973
974 publicaddrreply reply;
975 int bytes;
976
977 reply.version = NATPMVERSION;
978 reply.opcode = SERVERREPLYOP + PUBLICADDRREQ;
979 reply.result = SUCCESS;
980 reply.addr = lastassignaliasAddr;
981 reply.epoch = htonl(getuptime());
982
983 bytes = sendto (fd, (void*)&reply, sizeof(reply), 0, (struct sockaddr*)clientaddr, clientaddrlen);
984 if ( bytes != sizeof(reply) )
985 printf( "PORTMAP::problem sending portmap reply - opcode %d\n", reply.opcode );
986 }
987
988 /* SendPublicPortResponse */
989 /* response for portmap request and portmap removal request */
990 /* publicport <= 0 means error */
991 static void SendPublicPortResponse( int fd, struct sockaddr_in *clientaddr, int clientaddrlen, publicportreq *req, u_short publicport, int result)
992 {
993
994 int bytes;
995 publicportreply reply;
996
997 bzero(&reply, sizeof(publicportreply));
998 reply.version = NATPMVERSION;
999 reply.opcode = SERVERREPLYOP + req->opcode;
1000 if (result)
1001 /* error in port mapping */
1002 reply.result = htons(OUTOFRESOURCES);
1003 else
1004 reply.result = SUCCESS;
1005
1006 reply.epoch = htonl(getuptime());
1007
1008 reply.privateport = req->privateport;
1009
1010 /* adding or renewing a mapping */
1011 if ( req->lifetime ) {
1012 reply.publicport = publicport;
1013 reply.lifetime = req->lifetime;
1014 }
1015 bytes = sendto (fd, (void*)&reply, sizeof(publicportreply), 0, (struct sockaddr*)clientaddr, clientaddrlen);
1016 if ( bytes != sizeof(publicportreply) )
1017 printf( "PORTMAP::problem sending portmap reply - opcode %d\n", req->opcode );
1018 }
1019
1020 /* SendPortMapMulti */
1021 /* send multicast to local network for new alias address */
1022 static void SendPortMapMulti()
1023 {
1024
1025 publicaddrreply reply;
1026 int bytes;
1027 struct sockaddr_in multiaddr;
1028 int multisock;
1029 int i;
1030
1031 #define LOCALGROUP "224.0.0.1"
1032 numoftries++;
1033 memset(&multiaddr,0,sizeof(struct sockaddr_in));
1034 multiaddr.sin_family=AF_INET;
1035 multiaddr.sin_addr.s_addr=inet_addr(LOCALGROUP);
1036 multiaddr.sin_port=htons(NATPMP_ANNOUNCEMENT_PORT);
1037 reply.version = NATPMVERSION;
1038 reply.opcode = SERVERREPLYOP + PUBLICADDRREQ;
1039 reply.result = SUCCESS;
1040 reply.addr = lastassignaliasAddr;
1041 reply.epoch = 0;
1042
1043 /* send multicast to all forwarded interfaces */
1044 for ( i = 0; i < numofinterfaces; i++)
1045 {
1046 if (forwardedinterfaceaddr[i].s_addr == 0)
1047 {
1048 continue;
1049 }
1050 multisock = socket( AF_INET, SOCK_DGRAM, 0);
1051
1052 if ( multisock == -1 )
1053 {
1054 printf("cannot get socket for sending multicast\n");
1055 return;
1056 }
1057 if (setsockopt(multisock, IPPROTO_IP, IP_MULTICAST_IF, &forwardedinterfaceaddr[i], sizeof(struct in_addr)) < 0)
1058 {
1059 printf("setsockopt failed\n");
1060 close(multisock);
1061 continue;
1062 }
1063 bytes = sendto (multisock, (void*)&reply, sizeof(reply), 0, (struct sockaddr*)&multiaddr, sizeof(multiaddr));
1064 if ( bytes != sizeof(reply) )
1065 printf( "PORTMAP::problem sending multicast alias address - opcode %d\n", reply.opcode );
1066 close(multisock);
1067 }
1068
1069 }
1070
1071 /* double the time value */
1072 static void Doubletime( struct timeval *tvp)
1073 {
1074
1075 timeradd(tvp, tvp, tvp);
1076
1077 }
1078
1079 /* stop running natd timer */
1080 static void Stoptimer()
1081 {
1082 itval.it_value.tv_sec = 0;
1083 itval.it_value.tv_usec = 0;
1084 if (setitimer(ITIMER_REAL, &itval, (struct itimerval *)NULL) < 0)
1085 printf( "setitimer err: %d\n", errno);
1086 }
1087
1088 /* natdtimer */
1089 /* timer routine to send new public IP address */
1090 static void Natdtimer()
1091 {
1092 if ( !enable_natportmap )
1093 return;
1094
1095 SendPortMapMulti();
1096
1097 if ( numoftries < MAXRETRY ){
1098 Doubletime( &itval.it_value);
1099 itval.it_interval.tv_sec = 0;
1100 itval.it_interval.tv_usec = 0;
1101 if (setitimer(ITIMER_REAL, &itval, (struct itimerval *)NULL) < 0)
1102 printf( "setitimer err: %d\n", errno);
1103 }
1104 else
1105 {
1106 Stoptimer();
1107 return;
1108 }
1109
1110 }
1111
1112 /* NotifyPublicAddress */
1113 /* Advertise new public address */
1114 static void NotifyPublicAddress()
1115 {
1116 if ( numoftries < MAXRETRY)
1117 {
1118 /* there is an old timer running, cancel it */
1119 Stoptimer();
1120 }
1121 /* send up new timer */
1122 numoftries = 0;
1123 SendPortMapMulti();
1124 itval.it_value.tv_sec = 0;
1125 itval.it_value.tv_usec = TIMER_RATE;
1126 itval.it_interval.tv_sec = 0;
1127 itval.it_interval.tv_usec = 0;
1128 if (setitimer(ITIMER_REAL, &itval, (struct itimerval *)NULL) < 0)
1129 printf( "setitimer err: %d\n", errno);
1130
1131 }
1132
1133 /* DoPortMapping */
1134 /* find/add/remove port mapping from alias manager */
1135 void DoPortMapping( int fd, struct sockaddr_in *clientaddr, int clientaddrlen, publicportreq *req)
1136 {
1137 u_char proto = IPPROTO_TCP;
1138 int aliasport;
1139 struct in_addr inany = { INADDR_ANY };
1140
1141 if ( req->opcode == MAPUDPREQ)
1142 proto = IPPROTO_UDP;
1143 if ( req->lifetime == 0)
1144 {
1145 /* remove port mapping */
1146 if ( !FindAliasPortOut( clientaddr->sin_addr,
1147 inany,
1148 req->privateport,
1149 req->publicport,
1150 proto,
1151 ntohl(req->lifetime),
1152 0) )
1153 /* FindAliasPortOut returns no error, port successfully removed, return no error response to client */
1154 SendPublicPortResponse( fd, clientaddr, clientaddrlen, req, 0, 0 );
1155 else
1156 /* deleting port fails, return error */
1157 SendPublicPortResponse( fd, clientaddr, clientaddrlen, req, 0, -1 );
1158 }
1159 else
1160 {
1161 /* look for port mapping - public port is ignored in this case */
1162 /* create port mapping - map provided public port to private port if public port is not 0 */
1163 aliasport = FindAliasPortOut( clientaddr->sin_addr,
1164 inany, /* lastassignaliasAddr */
1165 req->privateport,
1166 0,
1167 proto,
1168 ntohl(req->lifetime),
1169 1);
1170 /* aliasport should be non zero if mapping is successfully, else -1 is returned, alias port shouldn't be zero???? */
1171 SendPublicPortResponse( fd, clientaddr, clientaddrlen, req, aliasport, 0 );
1172
1173 }
1174 }
1175
1176 /* HandlePortMap */
1177 /* handle all packets sent to NATPORTMAP port */
1178 static void HandlePortMap( int fd )
1179 {
1180 #define MAXBUFFERSIZE 100
1181
1182 struct sockaddr_in clientaddr;
1183 socklen_t clientaddrlen;
1184 unsigned char buffer[MAXBUFFERSIZE];
1185 int bytes;
1186 unsigned short result = SUCCESS;
1187 struct stdportmaprequest *req;
1188
1189 clientaddrlen = sizeof( clientaddr );
1190 bytes = recvfrom( fd, buffer, sizeof(buffer), 0, (struct sockaddr*)&clientaddr, &clientaddrlen);
1191 if ( bytes == -1 )
1192 {
1193 printf( "Read NATPM port error\n");
1194 return;
1195 }
1196 else if ( bytes < sizeof(stdportmaprequest) )
1197 {
1198 /* drop any requests that are too short */
1199 return;
1200 }
1201
1202 req = (struct stdportmaprequest*)buffer;
1203
1204 #ifdef DEBUG
1205 {
1206 int i;
1207
1208 printf("HandlePortMap from %s:%u length= %d: ", inet_ntoa(clientaddr.sin_addr), clientaddr.sin_port, bytes);
1209 for ( i = 0; i<bytes; i++)
1210 {
1211 printf("%02x", buffer[i]);
1212 }
1213 printf("\n");
1214 }
1215 #endif
1216
1217 /* drop any reply packets that we receive on the floor */
1218 if ( req->opcode >= SERVERREPLYOP )
1219 {
1220 return;
1221 }
1222
1223 /* check client version */
1224 if ( req->version > NATPMVERSION )
1225 result = NOTSUPPORTEDVERSION;
1226 else if ( !enable_natportmap )
1227 /* natd wasn't launched with portmapping enabled */
1228 result = NOTAUTHORIZED;
1229
1230 if ( result )
1231 {
1232 SendPortMapResponse( fd, &clientaddr, clientaddrlen, req->opcode, result );
1233 return;
1234 }
1235
1236 switch ( req->opcode )
1237 {
1238 case PUBLICADDRREQ:
1239 {
1240 if ( bytes == sizeof(stdportmaprequest) )
1241 SendPublicAddress(fd, &clientaddr, clientaddrlen);
1242 break;
1243 }
1244
1245 case MAPUDPREQ:
1246 case MAPTCPREQ:
1247 case MAPUDPTCPREQ:
1248 {
1249 if ( bytes == sizeof(publicportreq) )
1250 DoPortMapping( fd, &clientaddr, clientaddrlen, (publicportreq*)req);
1251 break;
1252 }
1253
1254
1255 default:
1256 SendPortMapResponse( fd, &clientaddr, clientaddrlen, req->opcode, UNSUPPORTEDOPCODE );
1257 }
1258
1259 }
1260
1261 #endif /* NATPORTMAP */
1262
1263 static void PrintPacket (struct ip* ip)
1264 {
1265 printf ("%s", FormatPacket (ip));
1266 }
1267
1268 static void SyslogPacket (struct ip* ip, int priority, const char *label)
1269 {
1270 syslog (priority, "%s %s", label, FormatPacket (ip));
1271 }
1272
1273 static char* FormatPacket (struct ip* ip)
1274 {
1275 static char buf[256];
1276 struct tcphdr* tcphdr;
1277 struct udphdr* udphdr;
1278 struct icmp* icmphdr;
1279 char src[20];
1280 char dst[20];
1281
1282 strlcpy (src, inet_ntoa (ip->ip_src), sizeof(src));
1283 strlcpy (dst, inet_ntoa (ip->ip_dst), sizeof(dst));
1284
1285 switch (ip->ip_p) {
1286 case IPPROTO_TCP:
1287 tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2));
1288 snprintf (buf, sizeof(buf), "[TCP] %s:%d -> %s:%d",
1289 src,
1290 ntohs (tcphdr->th_sport),
1291 dst,
1292 ntohs (tcphdr->th_dport));
1293 break;
1294
1295 case IPPROTO_UDP:
1296 udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2));
1297 snprintf (buf, sizeof(buf), "[UDP] %s:%d -> %s:%d",
1298 src,
1299 ntohs (udphdr->uh_sport),
1300 dst,
1301 ntohs (udphdr->uh_dport));
1302 break;
1303
1304 case IPPROTO_ICMP:
1305 icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2));
1306 snprintf (buf, sizeof(buf), "[ICMP] %s -> %s %u(%u)",
1307 src,
1308 dst,
1309 icmphdr->icmp_type,
1310 icmphdr->icmp_code);
1311 break;
1312
1313 default:
1314 snprintf (buf, sizeof(buf), "[%d] %s -> %s ", ip->ip_p, src, dst);
1315 break;
1316 }
1317
1318 return buf;
1319 }
1320
1321 static void
1322 SetAliasAddressFromIfName(const char *ifn)
1323 {
1324 size_t needed;
1325 int mib[6];
1326 char *buf, *lim, *next;
1327 struct if_msghdr *ifm;
1328 struct ifa_msghdr *ifam;
1329 struct sockaddr_dl *sdl;
1330 struct sockaddr_in *sin;
1331
1332 mib[0] = CTL_NET;
1333 mib[1] = PF_ROUTE;
1334 mib[2] = 0;
1335 mib[3] = AF_INET; /* Only IP addresses please */
1336 mib[4] = NET_RT_IFLIST;
1337 mib[5] = 0; /* ifIndex??? */
1338 /*
1339 * Get interface data.
1340 */
1341 if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
1342 err(1, "iflist-sysctl-estimate");
1343 if ((buf = malloc(needed)) == NULL)
1344 errx(1, "malloc failed");
1345 if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
1346 err(1, "iflist-sysctl-get");
1347 lim = buf + needed;
1348 /*
1349 * Loop through interfaces until one with
1350 * given name is found. This is done to
1351 * find correct interface index for routing
1352 * message processing.
1353 */
1354 ifIndex = 0;
1355 next = buf;
1356 while (next < lim) {
1357 ifm = (struct if_msghdr *)next;
1358 next += ifm->ifm_msglen;
1359 if (ifm->ifm_version != RTM_VERSION) {
1360 if (verbose)
1361 warnx("routing message version %d "
1362 "not understood", ifm->ifm_version);
1363 continue;
1364 }
1365 if (ifm->ifm_type == RTM_IFINFO) {
1366 sdl = (struct sockaddr_dl *)(ifm + 1);
1367 if (strlen(ifn) == sdl->sdl_nlen &&
1368 strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) {
1369 ifIndex = ifm->ifm_index;
1370 ifMTU = ifm->ifm_data.ifi_mtu;
1371 if (clampMSS)
1372 PacketAliasClampMSS(ifMTU - sizeof(struct tcphdr) - sizeof(struct ip));
1373 break;
1374 }
1375 }
1376 }
1377 if (!ifIndex)
1378 errx(1, "unknown interface name %s", ifn);
1379 /*
1380 * Get interface address.
1381 */
1382 if (aliasAddr.s_addr == INADDR_NONE) {
1383 sin = NULL;
1384 while (next < lim) {
1385 ifam = (struct ifa_msghdr *)next;
1386 next += ifam->ifam_msglen;
1387 if (ifam->ifam_version != RTM_VERSION) {
1388 if (verbose)
1389 warnx("routing message version %d "
1390 "not understood", ifam->ifam_version);
1391 continue;
1392 }
1393 if (ifam->ifam_type != RTM_NEWADDR)
1394 break;
1395 if (ifam->ifam_addrs & RTA_IFA) {
1396 int i;
1397 char *cp = (char *)(ifam + 1);
1398
1399 #define ROUNDUP(a) \
1400 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t))
1401 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
1402
1403 for (i = 1; i < RTA_IFA; i <<= 1)
1404 if (ifam->ifam_addrs & i)
1405 ADVANCE(cp, (struct sockaddr *)cp);
1406 if (((struct sockaddr *)cp)->sa_family == AF_INET) {
1407 sin = (struct sockaddr_in *)cp;
1408 break;
1409 }
1410 }
1411 }
1412 if (sin == NULL)
1413 errx(1, "%s: cannot get interface address", ifn);
1414
1415 PacketAliasSetAddress(sin->sin_addr);
1416 #ifdef NATPORTMAP
1417 if ( (enable_natportmap) && (sin->sin_addr.s_addr != lastassignaliasAddr.s_addr) )
1418 {
1419 lastassignaliasAddr.s_addr = sin->sin_addr.s_addr;
1420 /* make sure the timer handler was set before setting timer */
1421 if ( !Natdtimerset ){
1422 Natdtimerset = 1;
1423 signal(SIGALRM, Natdtimer);
1424 }
1425 NotifyPublicAddress();
1426 }
1427 #endif
1428 syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes",
1429 inet_ntoa(sin->sin_addr), ifMTU);
1430 }
1431
1432 free(buf);
1433 }
1434
1435 void Quit (const char* msg)
1436 {
1437 Warn (msg);
1438 exit (1);
1439 }
1440
1441 void Warn (const char* msg)
1442 {
1443 if (background)
1444 syslog (LOG_ALERT, "%s (%m)", msg);
1445 else
1446 warn ("%s", msg);
1447 }
1448
1449 static void RefreshAddr (int sig)
1450 {
1451 if (ifName)
1452 assignAliasAddr = 1;
1453 }
1454
1455 static void InitiateShutdown (int sig)
1456 {
1457 /*
1458 * Start timer to allow kernel gracefully
1459 * shutdown existing connections when system
1460 * is shut down.
1461 */
1462 siginterrupt(SIGALRM, 1);
1463 signal (SIGALRM, Shutdown);
1464 alarm (10);
1465 }
1466
1467 static void Shutdown (int sig)
1468 {
1469 running = 0;
1470 }
1471
1472 static void HandleInfo (int sig)
1473 {
1474 dumpinfo++;
1475 }
1476
1477 /*
1478 * Different options recognized by this program.
1479 */
1480
1481 enum Option {
1482
1483 PacketAliasOption,
1484 Verbose,
1485 InPort,
1486 OutPort,
1487 Port,
1488 AliasAddress,
1489 TargetAddress,
1490 InterfaceName,
1491 RedirectPort,
1492 RedirectProto,
1493 RedirectAddress,
1494 ConfigFile,
1495 DynamicMode,
1496 ClampMSS,
1497 ProxyRule,
1498 LogDenied,
1499 LogFacility,
1500 PunchFW,
1501 #ifdef NATPORTMAP
1502 NATPortMap,
1503 ToInterfaceName
1504 #endif
1505 };
1506
1507 enum Param {
1508
1509 YesNo,
1510 Numeric,
1511 String,
1512 None,
1513 Address,
1514 Service
1515 };
1516
1517 /*
1518 * Option information structure (used by ParseOption).
1519 */
1520
1521 struct OptionInfo {
1522
1523 enum Option type;
1524 int packetAliasOpt;
1525 enum Param parm;
1526 const char* parmDescription;
1527 const char* description;
1528 const char* name;
1529 const char* shortName;
1530 };
1531
1532 /*
1533 * Table of known options.
1534 */
1535
1536 static struct OptionInfo optionTable[] = {
1537
1538 { PacketAliasOption,
1539 PKT_ALIAS_UNREGISTERED_ONLY,
1540 YesNo,
1541 "[yes|no]",
1542 "alias only unregistered addresses",
1543 "unregistered_only",
1544 "u" },
1545
1546 { PacketAliasOption,
1547 PKT_ALIAS_LOG,
1548 YesNo,
1549 "[yes|no]",
1550 "enable logging",
1551 "log",
1552 "l" },
1553
1554 { PacketAliasOption,
1555 PKT_ALIAS_PROXY_ONLY,
1556 YesNo,
1557 "[yes|no]",
1558 "proxy only",
1559 "proxy_only",
1560 NULL },
1561
1562 { PacketAliasOption,
1563 PKT_ALIAS_REVERSE,
1564 YesNo,
1565 "[yes|no]",
1566 "operate in reverse mode",
1567 "reverse",
1568 NULL },
1569
1570 { PacketAliasOption,
1571 PKT_ALIAS_DENY_INCOMING,
1572 YesNo,
1573 "[yes|no]",
1574 "allow incoming connections",
1575 "deny_incoming",
1576 "d" },
1577
1578 { PacketAliasOption,
1579 PKT_ALIAS_USE_SOCKETS,
1580 YesNo,
1581 "[yes|no]",
1582 "use sockets to inhibit port conflict",
1583 "use_sockets",
1584 "s" },
1585
1586 { PacketAliasOption,
1587 PKT_ALIAS_SAME_PORTS,
1588 YesNo,
1589 "[yes|no]",
1590 "try to keep original port numbers for connections",
1591 "same_ports",
1592 "m" },
1593
1594 { Verbose,
1595 0,
1596 YesNo,
1597 "[yes|no]",
1598 "verbose mode, dump packet information",
1599 "verbose",
1600 "v" },
1601
1602 { DynamicMode,
1603 0,
1604 YesNo,
1605 "[yes|no]",
1606 "dynamic mode, automatically detect interface address changes",
1607 "dynamic",
1608 NULL },
1609
1610 { ClampMSS,
1611 0,
1612 YesNo,
1613 "[yes|no]",
1614 "enable TCP MSS clamping",
1615 "clamp_mss",
1616 NULL },
1617
1618 { InPort,
1619 0,
1620 Service,
1621 "number|service_name",
1622 "set port for incoming packets",
1623 "in_port",
1624 "i" },
1625
1626 { OutPort,
1627 0,
1628 Service,
1629 "number|service_name",
1630 "set port for outgoing packets",
1631 "out_port",
1632 "o" },
1633
1634 { Port,
1635 0,
1636 Service,
1637 "number|service_name",
1638 "set port (defaults to natd/divert)",
1639 "port",
1640 "p" },
1641
1642 { AliasAddress,
1643 0,
1644 Address,
1645 "x.x.x.x",
1646 "address to use for aliasing",
1647 "alias_address",
1648 "a" },
1649
1650 { TargetAddress,
1651 0,
1652 Address,
1653 "x.x.x.x",
1654 "address to use for incoming sessions",
1655 "target_address",
1656 "t" },
1657
1658 { InterfaceName,
1659 0,
1660 String,
1661 "network_if_name",
1662 "take aliasing address from interface",
1663 "interface",
1664 "n" },
1665
1666 { ProxyRule,
1667 0,
1668 String,
1669 "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
1670 "a.b.c.d:yyyy",
1671 "add transparent proxying / destination NAT",
1672 "proxy_rule",
1673 NULL },
1674
1675 { RedirectPort,
1676 0,
1677 String,
1678 "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
1679 " [remote_addr[:remote_port_range]]",
1680 "redirect a port (or ports) for incoming traffic",
1681 "redirect_port",
1682 NULL },
1683
1684 { RedirectProto,
1685 0,
1686 String,
1687 "proto local_addr [public_addr] [remote_addr]",
1688 "redirect packets of a given proto",
1689 "redirect_proto",
1690 NULL },
1691
1692 { RedirectAddress,
1693 0,
1694 String,
1695 "local_addr[,...] public_addr",
1696 "define mapping between local and public addresses",
1697 "redirect_address",
1698 NULL },
1699
1700 { ConfigFile,
1701 0,
1702 String,
1703 "file_name",
1704 "read options from configuration file",
1705 "config",
1706 "f" },
1707
1708 { LogDenied,
1709 0,
1710 YesNo,
1711 "[yes|no]",
1712 "enable logging of denied incoming packets",
1713 "log_denied",
1714 NULL },
1715
1716 { LogFacility,
1717 0,
1718 String,
1719 "facility",
1720 "name of syslog facility to use for logging",
1721 "log_facility",
1722 NULL },
1723
1724 { PunchFW,
1725 0,
1726 String,
1727 "basenumber:count",
1728 "punch holes in the firewall for incoming FTP/IRC DCC connections",
1729 "punch_fw",
1730 NULL },
1731
1732 #ifdef NATPORTMAP
1733 { NATPortMap,
1734 0,
1735 YesNo,
1736 "[yes|no]",
1737 "enable NATPortMap protocol",
1738 "enable_natportmap",
1739 NULL },
1740
1741 { ToInterfaceName,
1742 0,
1743 String,
1744 "network_if_name",
1745 "take aliasing address to interface",
1746 "natportmap_interface",
1747 NULL },
1748
1749 #endif
1750 };
1751
1752 static void ParseOption (const char* option, const char* parms)
1753 {
1754 int i;
1755 struct OptionInfo* info;
1756 int yesNoValue;
1757 int aliasValue;
1758 int numValue;
1759 u_short uNumValue;
1760 const char* strValue;
1761 struct in_addr addrValue;
1762 int max;
1763 char* end;
1764 CODE* fac_record = NULL;
1765 /*
1766 * Find option from table.
1767 */
1768 max = sizeof (optionTable) / sizeof (struct OptionInfo);
1769 for (i = 0, info = optionTable; i < max; i++, info++) {
1770
1771 if (!strcmp (info->name, option))
1772 break;
1773
1774 if (info->shortName)
1775 if (!strcmp (info->shortName, option))
1776 break;
1777 }
1778
1779 if (i >= max) {
1780
1781 warnx ("unknown option %s", option);
1782 Usage ();
1783 }
1784
1785 uNumValue = 0;
1786 yesNoValue = 0;
1787 numValue = 0;
1788 strValue = NULL;
1789 /*
1790 * Check parameters.
1791 */
1792 switch (info->parm) {
1793 case YesNo:
1794 if (!parms)
1795 parms = "yes";
1796
1797 if (!strcmp (parms, "yes"))
1798 yesNoValue = 1;
1799 else
1800 if (!strcmp (parms, "no"))
1801 yesNoValue = 0;
1802 else
1803 errx (1, "%s needs yes/no parameter", option);
1804 break;
1805
1806 case Service:
1807 if (!parms)
1808 errx (1, "%s needs service name or "
1809 "port number parameter",
1810 option);
1811
1812 uNumValue = StrToPort (parms, "divert");
1813 break;
1814
1815 case Numeric:
1816 if (parms)
1817 numValue = strtol (parms, &end, 10);
1818 else
1819 end = NULL;
1820
1821 if (end == parms)
1822 errx (1, "%s needs numeric parameter", option);
1823 break;
1824
1825 case String:
1826 strValue = parms;
1827 if (!strValue)
1828 errx (1, "%s needs parameter", option);
1829 break;
1830
1831 case None:
1832 if (parms)
1833 errx (1, "%s does not take parameters", option);
1834 break;
1835
1836 case Address:
1837 if (!parms)
1838 errx (1, "%s needs address/host parameter", option);
1839
1840 StrToAddr (parms, &addrValue);
1841 break;
1842 }
1843
1844 switch (info->type) {
1845 case PacketAliasOption:
1846
1847 aliasValue = yesNoValue ? info->packetAliasOpt : 0;
1848 PacketAliasSetMode (aliasValue, info->packetAliasOpt);
1849 break;
1850
1851 case Verbose:
1852 verbose = yesNoValue;
1853 break;
1854
1855 case DynamicMode:
1856 dynamicMode = yesNoValue;
1857 break;
1858
1859 case ClampMSS:
1860 clampMSS = yesNoValue;
1861 break;
1862
1863 case InPort:
1864 inPort = uNumValue;
1865 break;
1866
1867 case OutPort:
1868 outPort = uNumValue;
1869 break;
1870
1871 case Port:
1872 inOutPort = uNumValue;
1873 break;
1874
1875 case AliasAddress:
1876 memcpy (&aliasAddr, &addrValue, sizeof (struct in_addr));
1877 break;
1878
1879 case TargetAddress:
1880 PacketAliasSetTarget(addrValue);
1881 break;
1882
1883 case RedirectPort:
1884 SetupPortRedirect (strValue);
1885 break;
1886
1887 case RedirectProto:
1888 SetupProtoRedirect(strValue);
1889 break;
1890
1891 case RedirectAddress:
1892 SetupAddressRedirect (strValue);
1893 break;
1894
1895 case ProxyRule:
1896 PacketAliasProxyRule (strValue);
1897 break;
1898
1899 case InterfaceName:
1900 if (ifName)
1901 free (ifName);
1902
1903 ifName = strdup (strValue);
1904 break;
1905
1906 case ConfigFile:
1907 ReadConfigFile (strValue);
1908 break;
1909
1910 case LogDenied:
1911 logDropped = 1;
1912 break;
1913
1914 case LogFacility:
1915
1916 fac_record = facilitynames;
1917 while (fac_record->c_name != NULL) {
1918
1919 if (!strcmp (fac_record->c_name, strValue)) {
1920
1921 logFacility = fac_record->c_val;
1922 break;
1923
1924 }
1925 else
1926 fac_record++;
1927 }
1928
1929 if(fac_record->c_name == NULL)
1930 errx(1, "Unknown log facility name: %s", strValue);
1931
1932 break;
1933
1934 case PunchFW:
1935 SetupPunchFW(strValue);
1936 break;
1937
1938 #ifdef NATPORTMAP
1939 case NATPortMap:
1940 enable_natportmap = yesNoValue;
1941 break;
1942
1943
1944 case ToInterfaceName:
1945 {
1946 if (forwardedinterfacename != NULL)
1947 {
1948 if ( (forwardedinterfacename = realloc( forwardedinterfacename, (numofinterfaces+1) * sizeof(*forwardedinterfacename ))) == NULL ){
1949 printf("realloc error, cannot allocate memory for fowarded interface name.\n");
1950 return;
1951 }
1952 }
1953 else {
1954 if ( (forwardedinterfacename = malloc( sizeof(*forwardedinterfacename) )) == NULL ){
1955 printf("malloc error, cannot allocate memory for fowarded interface name.\n");
1956 return;
1957 }
1958 }
1959
1960 forwardedinterfacename[numofinterfaces] = strdup(strValue);
1961 numofinterfaces++;
1962
1963 break;
1964 }
1965
1966 #endif
1967
1968 }
1969 }
1970
1971 void ReadConfigFile (const char* fileName)
1972 {
1973 FILE* file;
1974 char *buf;
1975 size_t len;
1976 char *ptr, *p;
1977 char* option;
1978
1979 file = fopen (fileName, "r");
1980 if (!file)
1981 err(1, "cannot open config file %s", fileName);
1982
1983 while ((buf = fgetln(file, &len)) != NULL) {
1984 if (buf[len - 1] == '\n')
1985 buf[len - 1] = '\0';
1986 else
1987 errx(1, "config file format error: "
1988 "last line should end with newline");
1989
1990 /*
1991 * Check for comments, strip off trailing spaces.
1992 */
1993 if ((ptr = strchr(buf, '#')))
1994 *ptr = '\0';
1995 for (ptr = buf; isspace(*ptr); ++ptr)
1996 continue;
1997 if (*ptr == '\0')
1998 continue;
1999 for (p = strchr(buf, '\0'); isspace(*--p);)
2000 continue;
2001 *++p = '\0';
2002
2003 /*
2004 * Extract option name.
2005 */
2006 option = ptr;
2007 while (*ptr && !isspace (*ptr))
2008 ++ptr;
2009
2010 if (*ptr != '\0') {
2011
2012 *ptr = '\0';
2013 ++ptr;
2014 }
2015 /*
2016 * Skip white space between name and parms.
2017 */
2018 while (*ptr && isspace (*ptr))
2019 ++ptr;
2020
2021 ParseOption (option, *ptr ? ptr : NULL);
2022 }
2023
2024 fclose (file);
2025 }
2026
2027 static void Usage ()
2028 {
2029 int i;
2030 int max;
2031 struct OptionInfo* info;
2032
2033 fprintf (stderr, "Recognized options:\n\n");
2034
2035 max = sizeof (optionTable) / sizeof (struct OptionInfo);
2036 for (i = 0, info = optionTable; i < max; i++, info++) {
2037
2038 fprintf (stderr, "-%-20s %s\n", info->name,
2039 info->parmDescription);
2040
2041 if (info->shortName)
2042 fprintf (stderr, "-%-20s %s\n", info->shortName,
2043 info->parmDescription);
2044
2045 fprintf (stderr, " %s\n\n", info->description);
2046 }
2047
2048 exit (1);
2049 }
2050
2051 void SetupPortRedirect (const char* parms)
2052 {
2053 char buf[128];
2054 char* ptr;
2055 char* serverPool;
2056 struct in_addr localAddr;
2057 struct in_addr publicAddr;
2058 struct in_addr remoteAddr;
2059 port_range portRange;
2060 u_short localPort = 0;
2061 u_short publicPort = 0;
2062 u_short remotePort = 0;
2063 u_short numLocalPorts = 0;
2064 u_short numPublicPorts = 0;
2065 u_short numRemotePorts = 0;
2066 int proto;
2067 char* protoName;
2068 char* separator;
2069 int i;
2070 struct alias_link *link = NULL;
2071
2072 strlcpy (buf, parms, sizeof(buf));
2073 /*
2074 * Extract protocol.
2075 */
2076 protoName = strtok (buf, " \t");
2077 if (!protoName)
2078 errx (1, "redirect_port: missing protocol");
2079
2080 proto = StrToProto (protoName);
2081 /*
2082 * Extract local address.
2083 */
2084 ptr = strtok (NULL, " \t");
2085 if (!ptr)
2086 errx (1, "redirect_port: missing local address");
2087
2088 separator = strchr(ptr, ',');
2089 if (separator) { /* LSNAT redirection syntax. */
2090 localAddr.s_addr = INADDR_NONE;
2091 localPort = ~0;
2092 numLocalPorts = 1;
2093 serverPool = ptr;
2094 } else {
2095 if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 )
2096 errx (1, "redirect_port: invalid local port range");
2097
2098 localPort = GETLOPORT(portRange);
2099 numLocalPorts = GETNUMPORTS(portRange);
2100 serverPool = NULL;
2101 }
2102
2103 /*
2104 * Extract public port and optionally address.
2105 */
2106 ptr = strtok (NULL, " \t");
2107 if (!ptr)
2108 errx (1, "redirect_port: missing public port");
2109
2110 separator = strchr (ptr, ':');
2111 if (separator) {
2112 if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 )
2113 errx (1, "redirect_port: invalid public port range");
2114 }
2115 else {
2116 publicAddr.s_addr = INADDR_ANY;
2117 if (StrToPortRange (ptr, protoName, &portRange) != 0)
2118 errx (1, "redirect_port: invalid public port range");
2119 }
2120
2121 publicPort = GETLOPORT(portRange);
2122 numPublicPorts = GETNUMPORTS(portRange);
2123
2124 /*
2125 * Extract remote address and optionally port.
2126 */
2127 ptr = strtok (NULL, " \t");
2128 if (ptr) {
2129 separator = strchr (ptr, ':');
2130 if (separator) {
2131 if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0)
2132 errx (1, "redirect_port: invalid remote port range");
2133 } else {
2134 SETLOPORT(portRange, 0);
2135 SETNUMPORTS(portRange, 1);
2136 StrToAddr (ptr, &remoteAddr);
2137 }
2138 }
2139 else {
2140 SETLOPORT(portRange, 0);
2141 SETNUMPORTS(portRange, 1);
2142 remoteAddr.s_addr = INADDR_ANY;
2143 }
2144
2145 remotePort = GETLOPORT(portRange);
2146 numRemotePorts = GETNUMPORTS(portRange);
2147
2148 /*
2149 * Make sure port ranges match up, then add the redirect ports.
2150 */
2151 if (numLocalPorts != numPublicPorts)
2152 errx (1, "redirect_port: port ranges must be equal in size");
2153
2154 /* Remote port range is allowed to be '0' which means all ports. */
2155 if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0))
2156 errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
2157
2158 for (i = 0 ; i < numPublicPorts ; ++i) {
2159 /* If remotePort is all ports, set it to 0. */
2160 u_short remotePortCopy = remotePort + i;
2161 if (numRemotePorts == 1 && remotePort == 0)
2162 remotePortCopy = 0;
2163
2164 link = PacketAliasRedirectPort (localAddr,
2165 htons(localPort + i),
2166 remoteAddr,
2167 htons(remotePortCopy),
2168 publicAddr,
2169 htons(publicPort + i),
2170 proto);
2171 }
2172
2173 /*
2174 * Setup LSNAT server pool.
2175 */
2176 if (serverPool != NULL && link != NULL) {
2177 ptr = strtok(serverPool, ",");
2178 while (ptr != NULL) {
2179 if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0)
2180 errx(1, "redirect_port: invalid local port range");
2181
2182 localPort = GETLOPORT(portRange);
2183 if (GETNUMPORTS(portRange) != 1)
2184 errx(1, "redirect_port: local port must be single in this context");
2185 PacketAliasAddServer(link, localAddr, htons(localPort));
2186 ptr = strtok(NULL, ",");
2187 }
2188 }
2189 }
2190
2191 void
2192 SetupProtoRedirect(const char* parms)
2193 {
2194 char buf[128];
2195 char* ptr;
2196 struct in_addr localAddr;
2197 struct in_addr publicAddr;
2198 struct in_addr remoteAddr;
2199 int proto;
2200 char* protoName;
2201 struct protoent *protoent;
2202
2203 strlcpy (buf, parms, sizeof(buf));
2204 /*
2205 * Extract protocol.
2206 */
2207 protoName = strtok(buf, " \t");
2208 if (!protoName)
2209 errx(1, "redirect_proto: missing protocol");
2210
2211 protoent = getprotobyname(protoName);
2212 if (protoent == NULL)
2213 errx(1, "redirect_proto: unknown protocol %s", protoName);
2214 else
2215 proto = protoent->p_proto;
2216 /*
2217 * Extract local address.
2218 */
2219 ptr = strtok(NULL, " \t");
2220 if (!ptr)
2221 errx(1, "redirect_proto: missing local address");
2222 else
2223 StrToAddr(ptr, &localAddr);
2224 /*
2225 * Extract optional public address.
2226 */
2227 ptr = strtok(NULL, " \t");
2228 if (ptr)
2229 StrToAddr(ptr, &publicAddr);
2230 else
2231 publicAddr.s_addr = INADDR_ANY;
2232 /*
2233 * Extract optional remote address.
2234 */
2235 ptr = strtok(NULL, " \t");
2236 if (ptr)
2237 StrToAddr(ptr, &remoteAddr);
2238 else
2239 remoteAddr.s_addr = INADDR_ANY;
2240 /*
2241 * Create aliasing link.
2242 */
2243 (void)PacketAliasRedirectProto(localAddr, remoteAddr, publicAddr,
2244 proto);
2245 }
2246
2247 void SetupAddressRedirect (const char* parms)
2248 {
2249 char buf[128];
2250 char* ptr;
2251 char* separator;
2252 struct in_addr localAddr;
2253 struct in_addr publicAddr;
2254 char* serverPool;
2255 struct alias_link *link;
2256
2257 strlcpy (buf, parms, sizeof(buf));
2258 /*
2259 * Extract local address.
2260 */
2261 ptr = strtok (buf, " \t");
2262 if (!ptr)
2263 errx (1, "redirect_address: missing local address");
2264
2265 separator = strchr(ptr, ',');
2266 if (separator) { /* LSNAT redirection syntax. */
2267 localAddr.s_addr = INADDR_NONE;
2268 serverPool = ptr;
2269 } else {
2270 StrToAddr (ptr, &localAddr);
2271 serverPool = NULL;
2272 }
2273 /*
2274 * Extract public address.
2275 */
2276 ptr = strtok (NULL, " \t");
2277 if (!ptr)
2278 errx (1, "redirect_address: missing public address");
2279
2280 StrToAddr (ptr, &publicAddr);
2281 link = PacketAliasRedirectAddr(localAddr, publicAddr);
2282
2283 /*
2284 * Setup LSNAT server pool.
2285 */
2286 if (serverPool != NULL && link != NULL) {
2287 ptr = strtok(serverPool, ",");
2288 while (ptr != NULL) {
2289 StrToAddr(ptr, &localAddr);
2290 PacketAliasAddServer(link, localAddr, htons(~0));
2291 ptr = strtok(NULL, ",");
2292 }
2293 }
2294 }
2295
2296 void StrToAddr (const char* str, struct in_addr* addr)
2297 {
2298 struct hostent* hp;
2299
2300 if (inet_aton (str, addr))
2301 return;
2302
2303 hp = gethostbyname (str);
2304 if (!hp)
2305 errx (1, "unknown host %s", str);
2306
2307 memcpy (addr, hp->h_addr, sizeof (struct in_addr));
2308 }
2309
2310 u_short StrToPort (const char* str, const char* proto)
2311 {
2312 u_short port;
2313 struct servent* sp;
2314 char* end;
2315
2316 port = strtol (str, &end, 10);
2317 if (end != str)
2318 return htons (port);
2319
2320 sp = getservbyname (str, proto);
2321 if (!sp)
2322 errx (1, "unknown service %s/%s", str, proto);
2323
2324 return sp->s_port;
2325 }
2326
2327 int StrToPortRange (const char* str, const char* proto, port_range *portRange)
2328 {
2329 char* sep;
2330 struct servent* sp;
2331 char* end;
2332 u_short loPort;
2333 u_short hiPort;
2334
2335 /* First see if this is a service, return corresponding port if so. */
2336 sp = getservbyname (str,proto);
2337 if (sp) {
2338 SETLOPORT(*portRange, ntohs(sp->s_port));
2339 SETNUMPORTS(*portRange, 1);
2340 return 0;
2341 }
2342
2343 /* Not a service, see if it's a single port or port range. */
2344 sep = strchr (str, '-');
2345 if (sep == NULL) {
2346 SETLOPORT(*portRange, strtol(str, &end, 10));
2347 if (end != str) {
2348 /* Single port. */
2349 SETNUMPORTS(*portRange, 1);
2350 return 0;
2351 }
2352
2353 /* Error in port range field. */
2354 errx (1, "unknown service %s/%s", str, proto);
2355 }
2356
2357 /* Port range, get the values and sanity check. */
2358 sscanf (str, "%hu-%hu", &loPort, &hiPort);
2359 SETLOPORT(*portRange, loPort);
2360 SETNUMPORTS(*portRange, 0); /* Error by default */
2361 if (loPort <= hiPort)
2362 SETNUMPORTS(*portRange, hiPort - loPort + 1);
2363
2364 if (GETNUMPORTS(*portRange) == 0)
2365 errx (1, "invalid port range %s", str);
2366
2367 return 0;
2368 }
2369
2370
2371 int StrToProto (const char* str)
2372 {
2373 if (!strcmp (str, "tcp"))
2374 return IPPROTO_TCP;
2375
2376 if (!strcmp (str, "udp"))
2377 return IPPROTO_UDP;
2378
2379 errx (1, "unknown protocol %s. Expected tcp or udp", str);
2380 }
2381
2382 int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange)
2383 {
2384 char* ptr;
2385
2386 ptr = strchr (str, ':');
2387 if (!ptr)
2388 errx (1, "%s is missing port number", str);
2389
2390 *ptr = '\0';
2391 ++ptr;
2392
2393 StrToAddr (str, addr);
2394 return StrToPortRange (ptr, proto, portRange);
2395 }
2396
2397 static void
2398 SetupPunchFW(const char *strValue)
2399 {
2400 unsigned int base, num;
2401
2402 if (sscanf(strValue, "%u:%u", &base, &num) != 2)
2403 errx(1, "punch_fw: basenumber:count parameter required");
2404
2405 PacketAliasSetFWBase(base, num);
2406 (void)PacketAliasSetMode(PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);
2407 }