]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/natd/natd.c
zfs: merge openzfs/zfs@a9d6b0690
[FreeBSD/FreeBSD.git] / sbin / natd / natd.c
1 /*
2  * natd - Network Address Translation Daemon for FreeBSD.
3  *
4  * This software is provided free of charge, with no 
5  * warranty of any kind, either expressed or implied.
6  * Use at your own risk.
7  * 
8  * You may copy, modify and distribute this software (natd.c) freely.
9  *
10  * Ari Suutari <suutari@iki.fi>
11  */
12
13 #include <sys/cdefs.h>
14 __FBSDID("$FreeBSD$");
15
16 #define SYSLOG_NAMES
17
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <sys/sysctl.h>
21 #include <sys/time.h>
22 #include <sys/queue.h>
23
24 #include <netinet/in.h>
25 #include <netinet/in_systm.h>
26 #include <netinet/ip.h>
27 #include <netinet/tcp.h>
28 #include <netinet/udp.h>
29 #include <netinet/ip_icmp.h>
30 #include <net/if.h>
31 #include <net/if_dl.h>
32 #include <net/route.h>
33 #include <arpa/inet.h>
34
35 #include <alias.h>
36 #include <ctype.h>
37 #include <err.h>
38 #include <errno.h>
39 #include <netdb.h>
40 #include <signal.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <syslog.h>
45 #include <unistd.h>
46
47 #include "natd.h"
48
49 struct instance {
50         const char              *name;
51         struct libalias         *la;
52         LIST_ENTRY(instance)    list;
53
54         int                     ifIndex;
55         int                     assignAliasAddr;
56         char*                   ifName;
57         int                     logDropped;
58         u_short                 inPort;
59         u_short                 outPort;
60         u_short                 inOutPort;
61         struct in_addr          aliasAddr;
62         int                     ifMTU;
63         int                     aliasOverhead;
64         int                     dropIgnoredIncoming;
65         int                     divertIn;
66         int                     divertOut;
67         int                     divertInOut;
68 };
69
70 static LIST_HEAD(, instance) root = LIST_HEAD_INITIALIZER(root);
71
72 struct libalias *mla;
73 static struct instance *mip;
74 static int ninstance = 1;
75
76 /* 
77  * Default values for input and output
78  * divert socket ports.
79  */
80
81 #define DEFAULT_SERVICE "natd"
82
83 /*
84  * Definition of a port range, and macros to deal with values.
85  * FORMAT:  HI 16-bits == first port in range, 0 == all ports.
86  *          LO 16-bits == number of ports in range
87  * NOTES:   - Port values are not stored in network byte order.
88  */
89
90 typedef u_long port_range;
91
92 #define GETLOPORT(x)     ((x) >> 0x10)
93 #define GETNUMPORTS(x)   ((x) & 0x0000ffff)
94 #define GETHIPORT(x)     (GETLOPORT((x)) + GETNUMPORTS((x)))
95
96 /* Set y to be the low-port value in port_range variable x. */
97 #define SETLOPORT(x,y)   ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
98
99 /* Set y to be the number of ports in port_range variable x. */
100 #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y))
101
102 /*
103  * Function prototypes.
104  */
105
106 static void     DoAliasing (int fd, int direction);
107 static void     DaemonMode (void);
108 static void     HandleRoutingInfo (int fd);
109 static void     Usage (void);
110 static char*    FormatPacket (struct ip*);
111 static void     PrintPacket (struct ip*);
112 static void     SyslogPacket (struct ip*, int priority, const char *label);
113 static int      SetAliasAddressFromIfName (const char *ifName);
114 static void     InitiateShutdown (int);
115 static void     Shutdown (int);
116 static void     RefreshAddr (int);
117 static void     ParseOption (const char* option, const char* parms);
118 static void     ReadConfigFile (const char* fileName);
119 static void     SetupPortRedirect (const char* parms);
120 static void     SetupProtoRedirect(const char* parms);
121 static void     SetupAddressRedirect (const char* parms);
122 static void     StrToAddr (const char* str, struct in_addr* addr);
123 static u_short  StrToPort (const char* str, const char* proto);
124 static int      StrToPortRange (const char* str, const char* proto, port_range *portRange);
125 static int      StrToProto (const char* str);
126 static int      StrToAddrAndPortRange (char* str, struct in_addr* addr, char* proto, port_range *portRange);
127 static void     ParseArgs (int argc, char** argv);
128 static void     SetupPunchFW(const char *strValue);
129 static void     SetupSkinnyPort(const char *strValue);
130 static void     NewInstance(const char *name);
131 static void     DoGlobal (int fd);
132 static int      CheckIpfwRulenum(unsigned int rnum);
133
134 /*
135  * Globals.
136  */
137
138 static  int                     verbose;
139 static  int                     background;
140 static  int                     running;
141 static  int                     logFacility;
142
143 static  int                     dynamicMode;
144 static  int                     icmpSock;
145 static  int                     logIpfwDenied;
146 static  const char*             pidName;
147 static  int                     routeSock;
148 static  int                     globalPort;
149 static  int                     divertGlobal;
150 static  int                     exitDelay;
151
152
153 int main (int argc, char** argv)
154 {
155         struct sockaddr_in      addr;
156         fd_set                  readMask;
157         int                     fdMax;
158         int                     rval;
159 /* 
160  * Initialize packet aliasing software.
161  * Done already here to be able to alter option bits
162  * during command line and configuration file processing.
163  */
164         NewInstance("default");
165
166 /*
167  * Parse options.
168  */
169         verbose                 = 0;
170         background              = 0;
171         running                 = 1;
172         dynamicMode             = 0;
173         logFacility             = LOG_DAEMON;
174         logIpfwDenied           = -1;
175         pidName                 = PIDFILE;
176         routeSock               = -1;
177         icmpSock                = -1;
178         fdMax                   = -1;
179         divertGlobal            = -1;
180         exitDelay               = EXIT_DELAY;
181
182         ParseArgs (argc, argv);
183 /*
184  * Log ipfw(8) denied packets by default in verbose mode.
185  */
186         if (logIpfwDenied == -1)
187                 logIpfwDenied = verbose;
188 /*
189  * Open syslog channel.
190  */
191         openlog ("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0),
192                  logFacility);
193
194         LIST_FOREACH(mip, &root, list) {
195                 mla = mip->la;
196 /*
197  * If not doing the transparent proxying only,
198  * check that valid aliasing address has been given.
199  */
200                 if (mip->aliasAddr.s_addr == INADDR_NONE && mip->ifName == NULL &&
201                     !(LibAliasSetMode(mla, 0,0) & PKT_ALIAS_PROXY_ONLY))
202                         errx (1, "instance %s: aliasing address not given", mip->name);
203
204                 if (mip->aliasAddr.s_addr != INADDR_NONE && mip->ifName != NULL)
205                         errx (1, "both alias address and interface "
206                                  "name are not allowed");
207 /*
208  * Check that valid port number is known.
209  */
210                 if (mip->inPort != 0 || mip->outPort != 0)
211                         if (mip->inPort == 0 || mip->outPort == 0)
212                                 errx (1, "both input and output ports are required");
213
214                 if (mip->inPort == 0 && mip->outPort == 0 && mip->inOutPort == 0)
215                         ParseOption ("port", DEFAULT_SERVICE);
216
217 /*
218  * Check if ignored packets should be dropped.
219  */
220                 mip->dropIgnoredIncoming = LibAliasSetMode (mla, 0, 0);
221                 mip->dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING;
222 /*
223  * Create divert sockets. Use only one socket if -p was specified
224  * on command line. Otherwise, create separate sockets for
225  * outgoing and incoming connections.
226  */
227                 if (mip->inOutPort) {
228
229                         mip->divertInOut = socket(PF_DIVERT, SOCK_RAW, 0);
230                         if (mip->divertInOut == -1)
231                                 Quit ("Unable to create divert socket.");
232                         if (mip->divertInOut > fdMax)
233                                 fdMax = mip->divertInOut;
234
235                         mip->divertIn  = -1;
236                         mip->divertOut = -1;
237 /*
238  * Bind socket.
239  */
240
241                         addr.sin_family         = AF_INET;
242                         addr.sin_addr.s_addr    = INADDR_ANY;
243                         addr.sin_port           = mip->inOutPort;
244
245                         if (bind (mip->divertInOut,
246                                   (struct sockaddr*) &addr,
247                                   sizeof addr) == -1)
248                                 Quit ("Unable to bind divert socket.");
249                 }
250                 else {
251
252                         mip->divertIn = socket(PF_DIVERT, SOCK_RAW, 0);
253                         if (mip->divertIn == -1)
254                                 Quit ("Unable to create incoming divert socket.");
255                         if (mip->divertIn > fdMax)
256                                 fdMax = mip->divertIn;
257
258
259                         mip->divertOut = socket(PF_DIVERT, SOCK_RAW, 0);
260                         if (mip->divertOut == -1)
261                                 Quit ("Unable to create outgoing divert socket.");
262                         if (mip->divertOut > fdMax)
263                                 fdMax = mip->divertOut;
264
265                         mip->divertInOut = -1;
266
267 /*
268  * Bind divert sockets.
269  */
270
271                         addr.sin_family         = AF_INET;
272                         addr.sin_addr.s_addr    = INADDR_ANY;
273                         addr.sin_port           = mip->inPort;
274
275                         if (bind (mip->divertIn,
276                                   (struct sockaddr*) &addr,
277                                   sizeof addr) == -1)
278                                 Quit ("Unable to bind incoming divert socket.");
279
280                         addr.sin_family         = AF_INET;
281                         addr.sin_addr.s_addr    = INADDR_ANY;
282                         addr.sin_port           = mip->outPort;
283
284                         if (bind (mip->divertOut,
285                                   (struct sockaddr*) &addr,
286                                   sizeof addr) == -1)
287                                 Quit ("Unable to bind outgoing divert socket.");
288                 }
289 /*
290  * Create routing socket if interface name specified and in dynamic mode.
291  */
292                 if (mip->ifName) {
293                         if (dynamicMode) {
294
295                                 if (routeSock == -1)
296                                         routeSock = socket (PF_ROUTE, SOCK_RAW, 0);
297                                 if (routeSock == -1)
298                                         Quit ("Unable to create routing info socket.");
299                                 if (routeSock > fdMax)
300                                         fdMax = routeSock;
301
302                                 mip->assignAliasAddr = 1;
303                         }
304                         else {
305                                 do {
306                                         rval = SetAliasAddressFromIfName (mip->ifName);
307                                         if (background == 0 || dynamicMode == 0)
308                                                 break;
309                                         if (rval == EAGAIN)
310                                                 sleep(1);
311                                 } while (rval == EAGAIN);
312                                 if (rval != 0)
313                                         exit(1);
314                         }
315                 }
316
317         }
318         if (globalPort) {
319
320                 divertGlobal = socket(PF_DIVERT, SOCK_RAW, 0);
321                 if (divertGlobal == -1)
322                         Quit ("Unable to create divert socket.");
323                 if (divertGlobal > fdMax)
324                         fdMax = divertGlobal;
325
326 /*
327 * Bind socket.
328 */
329
330                 addr.sin_family         = AF_INET;
331                 addr.sin_addr.s_addr    = INADDR_ANY;
332                 addr.sin_port           = globalPort;
333
334                 if (bind (divertGlobal,
335                           (struct sockaddr*) &addr,
336                           sizeof addr) == -1)
337                         Quit ("Unable to bind global divert socket.");
338         }
339 /*
340  * Create socket for sending ICMP messages.
341  */
342         icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
343         if (icmpSock == -1)
344                 Quit ("Unable to create ICMP socket.");
345
346 /*
347  * And disable reads for the socket, otherwise it slowly fills
348  * up with received icmps which we do not use.
349  */
350         shutdown(icmpSock, SHUT_RD);
351
352 /*
353  * Become a daemon unless verbose mode was requested.
354  */
355         if (!verbose)
356                 DaemonMode ();
357 /*
358  * Catch signals to manage shutdown and
359  * refresh of interface address.
360  */
361         siginterrupt(SIGTERM, 1);
362         siginterrupt(SIGHUP, 1);
363         if (exitDelay)
364                 signal(SIGTERM, InitiateShutdown);
365         else
366                 signal(SIGTERM, Shutdown);
367         signal (SIGHUP, RefreshAddr);
368 /*
369  * Set alias address if it has been given.
370  */
371         mip = LIST_FIRST(&root);        /* XXX: simon */
372         LIST_FOREACH(mip, &root, list) {
373                 mla = mip->la;
374                 if (mip->aliasAddr.s_addr != INADDR_NONE)
375                         LibAliasSetAddress (mla, mip->aliasAddr);
376         }
377
378         while (running) {
379                 mip = LIST_FIRST(&root);        /* XXX: simon */
380
381                 if (mip->divertInOut != -1 && !mip->ifName && ninstance == 1) {
382 /*
383  * When using only one socket, just call 
384  * DoAliasing repeatedly to process packets.
385  */
386                         DoAliasing (mip->divertInOut, DONT_KNOW);
387                         continue;
388                 }
389 /* 
390  * Build read mask from socket descriptors to select.
391  */
392                 FD_ZERO (&readMask);
393 /*
394  * Check if new packets are available.
395  */
396                 LIST_FOREACH(mip, &root, list) {
397                         if (mip->divertIn != -1)
398                                 FD_SET (mip->divertIn, &readMask);
399
400                         if (mip->divertOut != -1)
401                                 FD_SET (mip->divertOut, &readMask);
402
403                         if (mip->divertInOut != -1)
404                                 FD_SET (mip->divertInOut, &readMask);
405                 }
406 /*
407  * Routing info is processed always.
408  */
409                 if (routeSock != -1)
410                         FD_SET (routeSock, &readMask);
411
412                 if (divertGlobal != -1)
413                         FD_SET (divertGlobal, &readMask);
414
415                 if (select (fdMax + 1,
416                             &readMask,
417                             NULL,
418                             NULL,
419                             NULL) == -1) {
420
421                         if (errno == EINTR)
422                                 continue;
423
424                         Quit ("Select failed.");
425                 }
426
427                 if (divertGlobal != -1)
428                         if (FD_ISSET (divertGlobal, &readMask))
429                                 DoGlobal (divertGlobal);
430                 LIST_FOREACH(mip, &root, list) {
431                         mla = mip->la;
432                         if (mip->divertIn != -1)
433                                 if (FD_ISSET (mip->divertIn, &readMask))
434                                         DoAliasing (mip->divertIn, INPUT);
435
436                         if (mip->divertOut != -1)
437                                 if (FD_ISSET (mip->divertOut, &readMask))
438                                         DoAliasing (mip->divertOut, OUTPUT);
439
440                         if (mip->divertInOut != -1) 
441                                 if (FD_ISSET (mip->divertInOut, &readMask))
442                                         DoAliasing (mip->divertInOut, DONT_KNOW);
443
444                 }
445                 if (routeSock != -1)
446                         if (FD_ISSET (routeSock, &readMask))
447                                 HandleRoutingInfo (routeSock);
448         }
449
450         if (background)
451                 unlink (pidName);
452
453         return 0;
454 }
455
456 static void DaemonMode(void)
457 {
458         FILE*   pidFile;
459
460         daemon (0, 0);
461         background = 1;
462
463         pidFile = fopen (pidName, "w");
464         if (pidFile) {
465
466                 fprintf (pidFile, "%d\n", getpid ());
467                 fclose (pidFile);
468         }
469 }
470
471 static void ParseArgs (int argc, char** argv)
472 {
473         int             arg;
474         char*           opt;
475         char            parmBuf[256];
476         int             len; /* bounds checking */
477
478         for (arg = 1; arg < argc; arg++) {
479
480                 opt  = argv[arg];
481                 if (*opt != '-') {
482
483                         warnx ("invalid option %s", opt);
484                         Usage ();
485                 }
486
487                 parmBuf[0] = '\0';
488                 len = 0;
489
490                 while (arg < argc - 1) {
491
492                         if (argv[arg + 1][0] == '-')
493                                 break;
494
495                         if (len) {
496                                 strncat (parmBuf, " ", sizeof(parmBuf) - (len + 1));
497                                 len += strlen(parmBuf + len);
498                         }
499
500                         ++arg;
501                         strncat (parmBuf, argv[arg], sizeof(parmBuf) - (len + 1));
502                         len += strlen(parmBuf + len);
503
504                 }
505
506                 ParseOption (opt + 1, (len ? parmBuf : NULL));
507
508         }
509 }
510
511 static void DoGlobal (int fd)
512 {
513         int                     bytes;
514         int                     origBytes;
515         char                    buf[IP_MAXPACKET];
516         struct sockaddr_in      addr;
517         int                     wrote;
518         socklen_t               addrSize;
519         struct ip*              ip;
520         char                    msgBuf[80];
521
522 /*
523  * Get packet from socket.
524  */
525         addrSize  = sizeof addr;
526         origBytes = recvfrom (fd,
527                               buf,
528                               sizeof buf,
529                               0,
530                               (struct sockaddr*) &addr,
531                               &addrSize);
532
533         if (origBytes == -1) {
534
535                 if (errno != EINTR)
536                         Warn ("read from divert socket failed");
537
538                 return;
539         }
540
541 #if 0
542         if (mip->assignAliasAddr) {
543                 if (SetAliasAddressFromIfName (mip->ifName) != 0)
544                         exit(1);
545                 mip->assignAliasAddr = 0;
546         }
547 #endif
548 /*
549  * This is an IP packet.
550  */
551         ip = (struct ip*) buf;
552
553         if (verbose) {
554 /*
555  * Print packet direction and protocol type.
556  */
557                 printf ("Glb ");
558
559                 switch (ip->ip_p) {
560                 case IPPROTO_TCP:
561                         printf ("[TCP]  ");
562                         break;
563
564                 case IPPROTO_UDP:
565                         printf ("[UDP]  ");
566                         break;
567
568                 case IPPROTO_ICMP:
569                         printf ("[ICMP] ");
570                         break;
571
572                 default:
573                         printf ("[%d]    ", ip->ip_p);
574                         break;
575                 }
576 /*
577  * Print addresses.
578  */
579                 PrintPacket (ip);
580         }
581
582         LIST_FOREACH(mip, &root, list) {
583                 mla = mip->la;
584                 if (LibAliasOutTry (mla, buf, IP_MAXPACKET, 0) != PKT_ALIAS_IGNORED)
585                         break;
586         }
587 /*
588  * Length might have changed during aliasing.
589  */
590         bytes = ntohs (ip->ip_len);
591 /*
592  * Update alias overhead size for outgoing packets.
593  */
594         if (mip != NULL && bytes - origBytes > mip->aliasOverhead)
595                 mip->aliasOverhead = bytes - origBytes;
596
597         if (verbose) {
598                 
599 /*
600  * Print addresses after aliasing.
601  */
602                 printf (" aliased to\n");
603                 printf ("           ");
604                 PrintPacket (ip);
605                 printf ("\n");
606         }
607
608 /*
609  * Put packet back for processing.
610  */
611         wrote = sendto (fd, 
612                         buf,
613                         bytes,
614                         0,
615                         (struct sockaddr*) &addr,
616                         sizeof addr);
617         
618         if (wrote != bytes) {
619
620                 if (errno == EMSGSIZE && mip != NULL) {
621
622                         if (mip->ifMTU != -1)
623                                 SendNeedFragIcmp (icmpSock,
624                                                   (struct ip*) buf,
625                                                   mip->ifMTU - mip->aliasOverhead);
626                 }
627                 else if (errno == EACCES && logIpfwDenied) {
628
629                         sprintf (msgBuf, "failed to write packet back");
630                         Warn (msgBuf);
631                 }
632         }
633 }
634
635
636 static void DoAliasing (int fd, int direction)
637 {
638         int                     bytes;
639         int                     origBytes;
640         char                    buf[IP_MAXPACKET];
641         struct sockaddr_in      addr;
642         int                     wrote;
643         int                     status;
644         socklen_t               addrSize;
645         struct ip*              ip;
646         char                    msgBuf[80];
647         int                     rval;
648
649         if (mip->assignAliasAddr) {
650                 do {
651                         rval = SetAliasAddressFromIfName (mip->ifName);
652                         if (background == 0 || dynamicMode == 0)
653                                 break;
654                         if (rval == EAGAIN)
655                                 sleep(1);
656                 } while (rval == EAGAIN);
657                 if (rval != 0)
658                         exit(1);
659                 mip->assignAliasAddr = 0;
660         }
661 /*
662  * Get packet from socket.
663  */
664         addrSize  = sizeof addr;
665         origBytes = recvfrom (fd,
666                               buf,
667                               sizeof buf,
668                               0,
669                               (struct sockaddr*) &addr,
670                               &addrSize);
671
672         if (origBytes == -1) {
673
674                 if (errno != EINTR)
675                         Warn ("read from divert socket failed");
676
677                 return;
678         }
679 /*
680  * This is an IP packet.
681  */
682         ip = (struct ip*) buf;
683         if (direction == DONT_KNOW) {
684                 if (addr.sin_addr.s_addr == INADDR_ANY)
685                         direction = OUTPUT;
686                 else
687                         direction = INPUT;
688         }
689
690         if (verbose) {
691 /*
692  * Print packet direction and protocol type.
693  */
694                 printf (direction == OUTPUT ? "Out " : "In  ");
695                 if (ninstance > 1)
696                         printf ("{%s}", mip->name);
697
698                 switch (ip->ip_p) {
699                 case IPPROTO_TCP:
700                         printf ("[TCP]  ");
701                         break;
702
703                 case IPPROTO_UDP:
704                         printf ("[UDP]  ");
705                         break;
706
707                 case IPPROTO_ICMP:
708                         printf ("[ICMP] ");
709                         break;
710
711                 default:
712                         printf ("[%d]    ", ip->ip_p);
713                         break;
714                 }
715 /*
716  * Print addresses.
717  */
718                 PrintPacket (ip);
719         }
720
721         if (direction == OUTPUT) {
722 /*
723  * Outgoing packets. Do aliasing.
724  */
725                 LibAliasOut (mla, buf, IP_MAXPACKET);
726         }
727         else {
728
729 /*
730  * Do aliasing.
731  */     
732                 status = LibAliasIn (mla, buf, IP_MAXPACKET);
733                 if (status == PKT_ALIAS_IGNORED &&
734                     mip->dropIgnoredIncoming) {
735
736                         if (verbose)
737                                 printf (" dropped.\n");
738
739                         if (mip->logDropped)
740                                 SyslogPacket (ip, LOG_WARNING, "denied");
741
742                         return;
743                 }
744         }
745 /*
746  * Length might have changed during aliasing.
747  */
748         bytes = ntohs (ip->ip_len);
749 /*
750  * Update alias overhead size for outgoing packets.
751  */
752         if (direction == OUTPUT &&
753             bytes - origBytes > mip->aliasOverhead)
754                 mip->aliasOverhead = bytes - origBytes;
755
756         if (verbose) {
757                 
758 /*
759  * Print addresses after aliasing.
760  */
761                 printf (" aliased to\n");
762                 printf ("           ");
763                 PrintPacket (ip);
764                 printf ("\n");
765         }
766
767 /*
768  * Put packet back for processing.
769  */
770         wrote = sendto (fd, 
771                         buf,
772                         bytes,
773                         0,
774                         (struct sockaddr*) &addr,
775                         sizeof addr);
776         
777         if (wrote != bytes) {
778
779                 if (errno == EMSGSIZE) {
780
781                         if (direction == OUTPUT &&
782                             mip->ifMTU != -1)
783                                 SendNeedFragIcmp (icmpSock,
784                                                   (struct ip*) buf,
785                                                   mip->ifMTU - mip->aliasOverhead);
786                 }
787                 else if (errno == EACCES && logIpfwDenied) {
788
789                         sprintf (msgBuf, "failed to write packet back");
790                         Warn (msgBuf);
791                 }
792         }
793 }
794
795 static void HandleRoutingInfo (int fd)
796 {
797         int                     bytes;
798         struct if_msghdr        ifMsg;
799 /*
800  * Get packet from socket.
801  */
802         bytes = read (fd, &ifMsg, sizeof ifMsg);
803         if (bytes == -1) {
804
805                 Warn ("read from routing socket failed");
806                 return;
807         }
808
809         if (ifMsg.ifm_version != RTM_VERSION) {
810
811                 Warn ("unexpected packet read from routing socket");
812                 return;
813         }
814
815         if (verbose)
816                 printf ("Routing message %#x received.\n", ifMsg.ifm_type);
817
818         if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO)) {
819                 LIST_FOREACH(mip, &root, list) {
820                         mla = mip->la;
821                         if (ifMsg.ifm_index == mip->ifIndex) {
822                                 if (verbose)
823                                         printf("Interface address/MTU has probably changed.\n");
824                                 mip->assignAliasAddr = 1;
825                         }
826                 }
827         }
828 }
829
830 static void PrintPacket (struct ip* ip)
831 {
832         printf ("%s", FormatPacket (ip));
833 }
834
835 static void SyslogPacket (struct ip* ip, int priority, const char *label)
836 {
837         syslog (priority, "%s %s", label, FormatPacket (ip));
838 }
839
840 static char* FormatPacket (struct ip* ip)
841 {
842         static char     buf[256];
843         struct tcphdr*  tcphdr;
844         struct udphdr*  udphdr;
845         struct icmp*    icmphdr;
846         char            src[20];
847         char            dst[20];
848
849         strcpy (src, inet_ntoa (ip->ip_src));
850         strcpy (dst, inet_ntoa (ip->ip_dst));
851
852         switch (ip->ip_p) {
853         case IPPROTO_TCP:
854                 tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2));
855                 sprintf (buf, "[TCP] %s:%d -> %s:%d",
856                               src,
857                               ntohs (tcphdr->th_sport),
858                               dst,
859                               ntohs (tcphdr->th_dport));
860                 break;
861
862         case IPPROTO_UDP:
863                 udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2));
864                 sprintf (buf, "[UDP] %s:%d -> %s:%d",
865                               src,
866                               ntohs (udphdr->uh_sport),
867                               dst,
868                               ntohs (udphdr->uh_dport));
869                 break;
870
871         case IPPROTO_ICMP:
872                 icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2));
873                 sprintf (buf, "[ICMP] %s -> %s %u(%u)",
874                               src,
875                               dst,
876                               icmphdr->icmp_type,
877                               icmphdr->icmp_code);
878                 break;
879
880         default:
881                 sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst);
882                 break;
883         }
884
885         return buf;
886 }
887
888 static int
889 SetAliasAddressFromIfName(const char *ifn)
890 {
891         size_t needed;
892         int mib[6];
893         char *buf, *lim, *next;
894         struct if_msghdr *ifm;
895         struct ifa_msghdr *ifam;
896         struct sockaddr_dl *sdl;
897         struct sockaddr_in *sin;
898
899         mib[0] = CTL_NET;
900         mib[1] = PF_ROUTE;
901         mib[2] = 0;
902         mib[3] = AF_INET;       /* Only IP addresses please */
903         mib[4] = NET_RT_IFLIST;
904         mib[5] = 0;             /* ifIndex??? */
905 /*
906  * Get interface data.
907  */
908         if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
909                 err(1, "iflist-sysctl-estimate");
910         if ((buf = malloc(needed)) == NULL)
911                 errx(1, "malloc failed");
912         if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1 && errno != ENOMEM)
913                 err(1, "iflist-sysctl-get");
914         lim = buf + needed;
915 /*
916  * Loop through interfaces until one with
917  * given name is found. This is done to
918  * find correct interface index for routing
919  * message processing.
920  */
921         mip->ifIndex    = 0;
922         next = buf;
923         while (next < lim) {
924                 ifm = (struct if_msghdr *)next;
925                 next += ifm->ifm_msglen;
926                 if (ifm->ifm_version != RTM_VERSION) {
927                         if (verbose)
928                                 warnx("routing message version %d "
929                                       "not understood", ifm->ifm_version);
930                         continue;
931                 }
932                 if (ifm->ifm_type == RTM_IFINFO) {
933                         sdl = (struct sockaddr_dl *)(ifm + 1);
934                         if (strlen(ifn) == sdl->sdl_nlen &&
935                             strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) {
936                                 mip->ifIndex = ifm->ifm_index;
937                                 mip->ifMTU = ifm->ifm_data.ifi_mtu;
938                                 break;
939                         }
940                 }
941         }
942         if (!mip->ifIndex)
943                 errx(1, "unknown interface name %s", ifn);
944 /*
945  * Get interface address.
946  */
947         sin = NULL;
948         while (next < lim) {
949                 ifam = (struct ifa_msghdr *)next;
950                 next += ifam->ifam_msglen;
951                 if (ifam->ifam_version != RTM_VERSION) {
952                         if (verbose)
953                                 warnx("routing message version %d "
954                                       "not understood", ifam->ifam_version);
955                         continue;
956                 }
957                 if (ifam->ifam_type != RTM_NEWADDR)
958                         break;
959                 if (ifam->ifam_addrs & RTA_IFA) {
960                         int i;
961                         char *cp = (char *)(ifam + 1);
962
963                         for (i = 1; i < RTA_IFA; i <<= 1)
964                                 if (ifam->ifam_addrs & i)
965                                         cp += SA_SIZE((struct sockaddr *)cp);
966                         if (((struct sockaddr *)cp)->sa_family == AF_INET) {
967                                 sin = (struct sockaddr_in *)cp;
968                                 break;
969                         }
970                 }
971         }
972         if (sin == NULL) {
973                 warnx("%s: cannot get interface address", ifn);
974                 free(buf);
975                 return EAGAIN;
976         }
977
978         LibAliasSetAddress(mla, sin->sin_addr);
979         syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes",
980                inet_ntoa(sin->sin_addr), mip->ifMTU);
981
982         free(buf);
983
984         return 0;
985 }
986
987 void Quit (const char* msg)
988 {
989         Warn (msg);
990         exit (1);
991 }
992
993 void Warn (const char* msg)
994 {
995         if (background)
996                 syslog (LOG_ALERT, "%s (%m)", msg);
997         else
998                 warn ("%s", msg);
999 }
1000
1001 static void RefreshAddr (int sig __unused)
1002 {
1003         LibAliasRefreshModules();
1004         if (mip != NULL && mip->ifName != NULL)
1005                 mip->assignAliasAddr = 1;
1006 }
1007
1008 static void InitiateShutdown (int sig __unused)
1009 {
1010 /*
1011  * Start timer to allow kernel gracefully
1012  * shutdown existing connections when system
1013  * is shut down.
1014  */
1015         siginterrupt(SIGALRM, 1);
1016         signal (SIGALRM, Shutdown);
1017         ualarm(exitDelay*1000, 1000);
1018 }
1019
1020 static void Shutdown (int sig __unused)
1021 {
1022         running = 0;
1023 }
1024
1025 /* 
1026  * Different options recognized by this program.
1027  */
1028
1029 enum Option {
1030
1031         LibAliasOption,
1032         Instance,
1033         Verbose,
1034         InPort,
1035         OutPort,
1036         Port,
1037         GlobalPort,
1038         AliasAddress,
1039         TargetAddress,
1040         InterfaceName,
1041         RedirectPort,
1042         RedirectProto,
1043         RedirectAddress,
1044         ConfigFile,
1045         DynamicMode,
1046         ProxyRule,
1047         LogDenied,
1048         LogFacility,
1049         PunchFW,
1050         SkinnyPort,
1051         LogIpfwDenied,
1052         PidFile,
1053         ExitDelay
1054 };
1055
1056 enum Param {
1057         
1058         YesNo,
1059         Numeric,
1060         String,
1061         None,
1062         Address,
1063         Service
1064 };
1065
1066 /*
1067  * Option information structure (used by ParseOption).
1068  */
1069
1070 struct OptionInfo {
1071         
1072         enum Option             type;
1073         int                     packetAliasOpt;
1074         enum Param              parm;
1075         const char*             parmDescription;
1076         const char*             description;
1077         const char*             name; 
1078         const char*             shortName;
1079 };
1080
1081 /*
1082  * Table of known options.
1083  */
1084
1085 static struct OptionInfo optionTable[] = {
1086
1087         { LibAliasOption,
1088                 PKT_ALIAS_UNREGISTERED_ONLY,
1089                 YesNo,
1090                 "[yes|no]",
1091                 "alias only unregistered addresses",
1092                 "unregistered_only",
1093                 "u" },
1094
1095         { LibAliasOption,
1096                 PKT_ALIAS_LOG,
1097                 YesNo,
1098                 "[yes|no]",
1099                 "enable logging",
1100                 "log",
1101                 "l" },
1102
1103         { LibAliasOption,
1104                 PKT_ALIAS_PROXY_ONLY,
1105                 YesNo,
1106                 "[yes|no]",
1107                 "proxy only",
1108                 "proxy_only",
1109                 NULL },
1110
1111         { LibAliasOption,
1112                 PKT_ALIAS_REVERSE,
1113                 YesNo,
1114                 "[yes|no]",
1115                 "operate in reverse mode",
1116                 "reverse",
1117                 NULL },
1118
1119         { LibAliasOption,
1120                 PKT_ALIAS_DENY_INCOMING,
1121                 YesNo,
1122                 "[yes|no]",
1123                 "allow incoming connections",
1124                 "deny_incoming",
1125                 "d" },
1126
1127         { LibAliasOption,
1128                 PKT_ALIAS_USE_SOCKETS,
1129                 YesNo,
1130                 "[yes|no]",
1131                 "use sockets to inhibit port conflict",
1132                 "use_sockets",
1133                 "s" },
1134
1135         { LibAliasOption,
1136                 PKT_ALIAS_SAME_PORTS,
1137                 YesNo,
1138                 "[yes|no]",
1139                 "try to keep original port numbers for connections",
1140                 "same_ports",
1141                 "m" },
1142
1143         { Verbose,
1144                 0,
1145                 YesNo,
1146                 "[yes|no]",
1147                 "verbose mode, dump packet information",
1148                 "verbose",
1149                 "v" },
1150         
1151         { DynamicMode,
1152                 0,
1153                 YesNo,
1154                 "[yes|no]",
1155                 "dynamic mode, automatically detect interface address changes",
1156                 "dynamic",
1157                 NULL },
1158         
1159         { InPort,
1160                 0,
1161                 Service,
1162                 "number|service_name",
1163                 "set port for incoming packets",
1164                 "in_port",
1165                 "i" },
1166         
1167         { OutPort,
1168                 0,
1169                 Service,
1170                 "number|service_name",
1171                 "set port for outgoing packets",
1172                 "out_port",
1173                 "o" },
1174         
1175         { Port,
1176                 0,
1177                 Service,
1178                 "number|service_name",
1179                 "set port (defaults to natd/divert)",
1180                 "port",
1181                 "p" },
1182         
1183         { GlobalPort,
1184                 0,
1185                 Service,
1186                 "number|service_name",
1187                 "set globalport",
1188                 "globalport",
1189                 NULL },
1190         
1191         { AliasAddress,
1192                 0,
1193                 Address,
1194                 "x.x.x.x",
1195                 "address to use for aliasing",
1196                 "alias_address",
1197                 "a" },
1198         
1199         { TargetAddress,
1200                 0,
1201                 Address,
1202                 "x.x.x.x",
1203                 "address to use for incoming sessions",
1204                 "target_address",
1205                 "t" },
1206         
1207         { InterfaceName,
1208                 0,
1209                 String,
1210                 "network_if_name",
1211                 "take aliasing address from interface",
1212                 "interface",
1213                 "n" },
1214
1215         { ProxyRule,
1216                 0,
1217                 String,
1218                 "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
1219                 "a.b.c.d:yyyy",
1220                 "add transparent proxying / destination NAT",
1221                 "proxy_rule",
1222                 NULL },
1223
1224         { RedirectPort,
1225                 0,
1226                 String,
1227                 "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
1228                 " [remote_addr[:remote_port_range]]",
1229                 "redirect a port (or ports) for incoming traffic",
1230                 "redirect_port",
1231                 NULL },
1232
1233         { RedirectProto,
1234                 0,
1235                 String,
1236                 "proto local_addr [public_addr] [remote_addr]",
1237                 "redirect packets of a given proto",
1238                 "redirect_proto",
1239                 NULL },
1240
1241         { RedirectAddress,
1242                 0,
1243                 String,
1244                 "local_addr[,...] public_addr",
1245                 "define mapping between local and public addresses",
1246                 "redirect_address",
1247                 NULL },
1248
1249         { ConfigFile,
1250                 0,
1251                 String,
1252                 "file_name",
1253                 "read options from configuration file",
1254                 "config",
1255                 "f" },
1256
1257         { LogDenied,
1258                 0,
1259                 YesNo,
1260                 "[yes|no]",
1261                 "enable logging of denied incoming packets",
1262                 "log_denied",
1263                 NULL },
1264
1265         { LogFacility,
1266                 0,
1267                 String,
1268                 "facility",
1269                 "name of syslog facility to use for logging",
1270                 "log_facility",
1271                 NULL },
1272
1273         { PunchFW,
1274                 0,
1275                 String,
1276                 "basenumber:count",
1277                 "punch holes in the firewall for incoming FTP/IRC DCC connections",
1278                 "punch_fw",
1279                 NULL },
1280
1281         { SkinnyPort,
1282                 0,
1283                 String,
1284                 "port",
1285                 "set the TCP port for use with the Skinny Station protocol",
1286                 "skinny_port",
1287                 NULL },
1288
1289         { LogIpfwDenied,
1290                 0,
1291                 YesNo,
1292                 "[yes|no]",
1293                 "log packets converted by natd, but denied by ipfw",
1294                 "log_ipfw_denied",
1295                 NULL },
1296
1297         { PidFile,
1298                 0,
1299                 String,
1300                 "file_name",
1301                 "store PID in an alternate file",
1302                 "pid_file",
1303                 "P" },
1304         { Instance,
1305                 0,
1306                 String,
1307                 "instance name",
1308                 "name of aliasing engine instance",
1309                 "instance",
1310                 NULL },
1311         { ExitDelay,
1312                 0,
1313                 Numeric,
1314                 "ms",
1315                 "delay in ms before daemon exit after signal",
1316                 "exit_delay",
1317                 NULL },
1318 };
1319         
1320 static void ParseOption (const char* option, const char* parms)
1321 {
1322         int                     i;
1323         struct OptionInfo*      info;
1324         int                     yesNoValue;
1325         int                     aliasValue;
1326         int                     numValue;
1327         u_short                 uNumValue;
1328         const char*             strValue;
1329         struct in_addr          addrValue;
1330         int                     max;
1331         char*                   end;
1332         const CODE*             fac_record = NULL;
1333 /*
1334  * Find option from table.
1335  */
1336         max = sizeof (optionTable) / sizeof (struct OptionInfo);
1337         for (i = 0, info = optionTable; i < max; i++, info++) {
1338
1339                 if (!strcmp (info->name, option))
1340                         break;
1341
1342                 if (info->shortName)
1343                         if (!strcmp (info->shortName, option))
1344                                 break;
1345         }
1346
1347         if (i >= max) {
1348
1349                 warnx ("unknown option %s", option);
1350                 Usage ();
1351         }
1352
1353         uNumValue       = 0;
1354         yesNoValue      = 0;
1355         numValue        = 0;
1356         strValue        = NULL;
1357 /*
1358  * Check parameters.
1359  */
1360         switch (info->parm) {
1361         case YesNo:
1362                 if (!parms)
1363                         parms = "yes";
1364
1365                 if (!strcmp (parms, "yes"))
1366                         yesNoValue = 1;
1367                 else
1368                         if (!strcmp (parms, "no"))
1369                                 yesNoValue = 0;
1370                         else
1371                                 errx (1, "%s needs yes/no parameter", option);
1372                 break;
1373
1374         case Service:
1375                 if (!parms)
1376                         errx (1, "%s needs service name or "
1377                                  "port number parameter",
1378                                  option);
1379
1380                 uNumValue = StrToPort (parms, "divert");
1381                 break;
1382
1383         case Numeric:
1384                 if (parms)
1385                         numValue = strtol (parms, &end, 10);
1386                 else
1387                         end = NULL;
1388
1389                 if (end == parms)
1390                         errx (1, "%s needs numeric parameter", option);
1391                 break;
1392
1393         case String:
1394                 strValue = parms;
1395                 if (!strValue)
1396                         errx (1, "%s needs parameter", option);
1397                 break;
1398
1399         case None:
1400                 if (parms)
1401                         errx (1, "%s does not take parameters", option);
1402                 break;
1403
1404         case Address:
1405                 if (!parms)
1406                         errx (1, "%s needs address/host parameter", option);
1407
1408                 StrToAddr (parms, &addrValue);
1409                 break;
1410         }
1411
1412         switch (info->type) {
1413         case LibAliasOption:
1414         
1415                 aliasValue = yesNoValue ? info->packetAliasOpt : 0;
1416                 LibAliasSetMode (mla, aliasValue, info->packetAliasOpt);
1417                 break;
1418
1419         case Verbose:
1420                 verbose = yesNoValue;
1421                 break;
1422
1423         case DynamicMode:
1424                 dynamicMode = yesNoValue;
1425                 break;
1426
1427         case InPort:
1428                 mip->inPort = uNumValue;
1429                 break;
1430
1431         case OutPort:
1432                 mip->outPort = uNumValue;
1433                 break;
1434
1435         case Port:
1436                 mip->inOutPort = uNumValue;
1437                 break;
1438
1439         case GlobalPort:
1440                 globalPort = uNumValue;
1441                 break;
1442
1443         case AliasAddress:
1444                 memcpy (&mip->aliasAddr, &addrValue, sizeof (struct in_addr));
1445                 break;
1446
1447         case TargetAddress:
1448                 LibAliasSetTarget(mla, addrValue);
1449                 break;
1450
1451         case RedirectPort:
1452                 SetupPortRedirect (strValue);
1453                 break;
1454
1455         case RedirectProto:
1456                 SetupProtoRedirect(strValue);
1457                 break;
1458
1459         case RedirectAddress:
1460                 SetupAddressRedirect (strValue);
1461                 break;
1462
1463         case ProxyRule:
1464                 LibAliasProxyRule (mla, strValue);
1465                 break;
1466
1467         case InterfaceName:
1468                 if (mip->ifName)
1469                         free (mip->ifName);
1470
1471                 mip->ifName = strdup (strValue);
1472                 break;
1473
1474         case ConfigFile:
1475                 ReadConfigFile (strValue);
1476                 break;
1477
1478         case LogDenied:
1479                 mip->logDropped = yesNoValue;
1480                 break;
1481
1482         case LogFacility:
1483
1484                 fac_record = facilitynames;
1485                 while (fac_record->c_name != NULL) {
1486
1487                         if (!strcmp (fac_record->c_name, strValue)) {
1488
1489                                 logFacility = fac_record->c_val;
1490                                 break;
1491
1492                         }
1493                         else
1494                                 fac_record++;
1495                 }
1496
1497                 if(fac_record->c_name == NULL)
1498                         errx(1, "Unknown log facility name: %s", strValue);     
1499
1500                 break;
1501
1502         case PunchFW:
1503                 SetupPunchFW(strValue);
1504                 break;
1505
1506         case SkinnyPort:
1507                 SetupSkinnyPort(strValue);
1508                 break;
1509
1510         case LogIpfwDenied:
1511                 logIpfwDenied = yesNoValue;
1512                 break;
1513
1514         case PidFile:
1515                 pidName = strdup (strValue);
1516                 break;
1517         case Instance:
1518                 NewInstance(strValue);
1519                 break;
1520         case ExitDelay:
1521                 if (numValue < 0 || numValue > MAX_EXIT_DELAY)
1522                         errx(1, "Incorrect exit delay: %d", numValue);  
1523                 exitDelay = numValue;
1524                 break;
1525         }
1526 }
1527
1528 void ReadConfigFile (const char* fileName)
1529 {
1530         FILE*   file;
1531         char    *buf;
1532         size_t  len;
1533         char    *ptr, *p;
1534         char*   option;
1535
1536         file = fopen (fileName, "r");
1537         if (!file)
1538                 err(1, "cannot open config file %s", fileName);
1539
1540         while ((buf = fgetln(file, &len)) != NULL) {
1541                 if (buf[len - 1] == '\n')
1542                         buf[len - 1] = '\0';
1543                 else
1544                         errx(1, "config file format error: "
1545                                 "last line should end with newline");
1546
1547 /*
1548  * Check for comments, strip off trailing spaces.
1549  */
1550                 if ((ptr = strchr(buf, '#')))
1551                         *ptr = '\0';
1552                 for (ptr = buf; isspace(*ptr); ++ptr)
1553                         continue;
1554                 if (*ptr == '\0')
1555                         continue;
1556                 for (p = strchr(buf, '\0'); isspace(*--p);)
1557                         continue;
1558                 *++p = '\0';
1559
1560 /*
1561  * Extract option name.
1562  */
1563                 option = ptr;
1564                 while (*ptr && !isspace (*ptr))
1565                         ++ptr;
1566
1567                 if (*ptr != '\0') {
1568
1569                         *ptr = '\0';
1570                         ++ptr;
1571                 }
1572 /*
1573  * Skip white space between name and parms.
1574  */
1575                 while (*ptr && isspace (*ptr))
1576                         ++ptr;
1577
1578                 ParseOption (option, *ptr ? ptr : NULL);
1579         }
1580
1581         fclose (file);
1582 }
1583
1584 static void Usage(void)
1585 {
1586         int                     i;
1587         int                     max;
1588         struct OptionInfo*      info;
1589
1590         fprintf (stderr, "Recognized options:\n\n");
1591
1592         max = sizeof (optionTable) / sizeof (struct OptionInfo);
1593         for (i = 0, info = optionTable; i < max; i++, info++) {
1594
1595                 fprintf (stderr, "-%-20s %s\n", info->name,
1596                                                 info->parmDescription);
1597
1598                 if (info->shortName)
1599                         fprintf (stderr, "-%-20s %s\n", info->shortName,
1600                                                         info->parmDescription);
1601
1602                 fprintf (stderr, "      %s\n\n", info->description);
1603         }
1604
1605         exit (1);
1606 }
1607
1608 void SetupPortRedirect (const char* parms)
1609 {
1610         char            *buf;
1611         char*           ptr;
1612         char*           serverPool;
1613         struct in_addr  localAddr;
1614         struct in_addr  publicAddr;
1615         struct in_addr  remoteAddr;
1616         port_range      portRange;
1617         u_short         localPort      = 0;
1618         u_short         publicPort     = 0;
1619         u_short         remotePort     = 0;
1620         u_short         numLocalPorts  = 0;
1621         u_short         numPublicPorts = 0;
1622         u_short         numRemotePorts = 0;
1623         int             proto;
1624         char*           protoName;
1625         char*           separator;
1626         int             i;
1627         struct alias_link *aliaslink = NULL;
1628
1629         buf = strdup (parms);
1630         if (!buf)
1631                 errx (1, "redirect_port: strdup() failed");
1632 /*
1633  * Extract protocol.
1634  */
1635         protoName = strtok (buf, " \t");
1636         if (!protoName)
1637                 errx (1, "redirect_port: missing protocol");
1638
1639         proto = StrToProto (protoName);
1640 /*
1641  * Extract local address.
1642  */
1643         ptr = strtok (NULL, " \t");
1644         if (!ptr)
1645                 errx (1, "redirect_port: missing local address");
1646
1647         separator = strchr(ptr, ',');
1648         if (separator) {                /* LSNAT redirection syntax. */
1649                 localAddr.s_addr = INADDR_NONE;
1650                 localPort = ~0;
1651                 numLocalPorts = 1;
1652                 serverPool = ptr;
1653         } else {
1654                 if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 )
1655                         errx (1, "redirect_port: invalid local port range");
1656
1657                 localPort     = GETLOPORT(portRange);
1658                 numLocalPorts = GETNUMPORTS(portRange);
1659                 serverPool = NULL;
1660         }
1661
1662 /*
1663  * Extract public port and optionally address.
1664  */
1665         ptr = strtok (NULL, " \t");
1666         if (!ptr)
1667                 errx (1, "redirect_port: missing public port");
1668
1669         separator = strchr (ptr, ':');
1670         if (separator) {
1671                 if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 )
1672                         errx (1, "redirect_port: invalid public port range");
1673         }
1674         else {
1675                 publicAddr.s_addr = INADDR_ANY;
1676                 if (StrToPortRange (ptr, protoName, &portRange) != 0)
1677                         errx (1, "redirect_port: invalid public port range");
1678         }
1679
1680         publicPort     = GETLOPORT(portRange);
1681         numPublicPorts = GETNUMPORTS(portRange);
1682
1683 /*
1684  * Extract remote address and optionally port.
1685  */
1686         ptr = strtok (NULL, " \t");
1687         if (ptr) {
1688                 separator = strchr (ptr, ':');
1689                 if (separator) {
1690                         if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0)
1691                                 errx (1, "redirect_port: invalid remote port range");
1692                 } else {
1693                         SETLOPORT(portRange, 0);
1694                         SETNUMPORTS(portRange, 1);
1695                         StrToAddr (ptr, &remoteAddr);
1696                 }
1697         }
1698         else {
1699                 SETLOPORT(portRange, 0);
1700                 SETNUMPORTS(portRange, 1);
1701                 remoteAddr.s_addr = INADDR_ANY;
1702         }
1703
1704         remotePort     = GETLOPORT(portRange);
1705         numRemotePorts = GETNUMPORTS(portRange);
1706
1707 /*
1708  * Make sure port ranges match up, then add the redirect ports.
1709  */
1710         if (numLocalPorts != numPublicPorts)
1711                 errx (1, "redirect_port: port ranges must be equal in size");
1712
1713         /* Remote port range is allowed to be '0' which means all ports. */
1714         if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0))
1715                 errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
1716
1717         for (i = 0 ; i < numPublicPorts ; ++i) {
1718                 /* If remotePort is all ports, set it to 0. */
1719                 u_short remotePortCopy = remotePort + i;
1720                 if (numRemotePorts == 1 && remotePort == 0)
1721                         remotePortCopy = 0;
1722
1723                 aliaslink = LibAliasRedirectPort (mla, localAddr,
1724                                                 htons(localPort + i),
1725                                                 remoteAddr,
1726                                                 htons(remotePortCopy),
1727                                                 publicAddr,
1728                                                 htons(publicPort + i),
1729                                                 proto);
1730         }
1731
1732 /*
1733  * Setup LSNAT server pool.
1734  */
1735         if (serverPool != NULL && aliaslink != NULL) {
1736                 ptr = strtok(serverPool, ",");
1737                 while (ptr != NULL) {
1738                         if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0)
1739                                 errx(1, "redirect_port: invalid local port range");
1740
1741                         localPort = GETLOPORT(portRange);
1742                         if (GETNUMPORTS(portRange) != 1)
1743                                 errx(1, "redirect_port: local port must be single in this context");
1744                         LibAliasAddServer(mla, aliaslink, localAddr, htons(localPort));
1745                         ptr = strtok(NULL, ",");
1746                 }
1747         }
1748         
1749         free (buf);
1750 }
1751
1752 void
1753 SetupProtoRedirect(const char* parms)
1754 {
1755         char            *buf;
1756         char*           ptr;
1757         struct in_addr  localAddr;
1758         struct in_addr  publicAddr;
1759         struct in_addr  remoteAddr;
1760         int             proto;
1761         char*           protoName;
1762         struct protoent *protoent;
1763
1764         buf = strdup (parms);
1765         if (!buf)
1766                 errx (1, "redirect_port: strdup() failed");
1767 /*
1768  * Extract protocol.
1769  */
1770         protoName = strtok(buf, " \t");
1771         if (!protoName)
1772                 errx(1, "redirect_proto: missing protocol");
1773
1774         protoent = getprotobyname(protoName);
1775         if (protoent == NULL)
1776                 errx(1, "redirect_proto: unknown protocol %s", protoName);
1777         else
1778                 proto = protoent->p_proto;
1779 /*
1780  * Extract local address.
1781  */
1782         ptr = strtok(NULL, " \t");
1783         if (!ptr)
1784                 errx(1, "redirect_proto: missing local address");
1785         else
1786                 StrToAddr(ptr, &localAddr);
1787 /*
1788  * Extract optional public address.
1789  */
1790         ptr = strtok(NULL, " \t");
1791         if (ptr)
1792                 StrToAddr(ptr, &publicAddr);
1793         else
1794                 publicAddr.s_addr = INADDR_ANY;
1795 /*
1796  * Extract optional remote address.
1797  */
1798         ptr = strtok(NULL, " \t");
1799         if (ptr)
1800                 StrToAddr(ptr, &remoteAddr);
1801         else
1802                 remoteAddr.s_addr = INADDR_ANY;
1803 /*
1804  * Create aliasing link.
1805  */
1806         (void)LibAliasRedirectProto(mla, localAddr, remoteAddr, publicAddr,
1807                                        proto);
1808
1809         free (buf);
1810 }
1811
1812 void SetupAddressRedirect (const char* parms)
1813 {
1814         char            *buf;
1815         char*           ptr;
1816         char*           separator;
1817         struct in_addr  localAddr;
1818         struct in_addr  publicAddr;
1819         char*           serverPool;
1820         struct alias_link *aliaslink;
1821
1822         buf = strdup (parms);
1823         if (!buf)
1824                 errx (1, "redirect_port: strdup() failed");
1825 /*
1826  * Extract local address.
1827  */
1828         ptr = strtok (buf, " \t");
1829         if (!ptr)
1830                 errx (1, "redirect_address: missing local address");
1831
1832         separator = strchr(ptr, ',');
1833         if (separator) {                /* LSNAT redirection syntax. */
1834                 localAddr.s_addr = INADDR_NONE;
1835                 serverPool = ptr;
1836         } else {
1837                 StrToAddr (ptr, &localAddr);
1838                 serverPool = NULL;
1839         }
1840 /*
1841  * Extract public address.
1842  */
1843         ptr = strtok (NULL, " \t");
1844         if (!ptr)
1845                 errx (1, "redirect_address: missing public address");
1846
1847         StrToAddr (ptr, &publicAddr);
1848         aliaslink = LibAliasRedirectAddr(mla, localAddr, publicAddr);
1849
1850 /*
1851  * Setup LSNAT server pool.
1852  */
1853         if (serverPool != NULL && aliaslink != NULL) {
1854                 ptr = strtok(serverPool, ",");
1855                 while (ptr != NULL) {
1856                         StrToAddr(ptr, &localAddr);
1857                         LibAliasAddServer(mla, aliaslink, localAddr, htons(~0));
1858                         ptr = strtok(NULL, ",");
1859                 }
1860         }
1861
1862         free (buf);
1863 }
1864
1865 void StrToAddr (const char* str, struct in_addr* addr)
1866 {
1867         struct hostent* hp;
1868
1869         if (inet_aton (str, addr))
1870                 return;
1871
1872         hp = gethostbyname (str);
1873         if (!hp)
1874                 errx (1, "unknown host %s", str);
1875
1876         memcpy (addr, hp->h_addr, sizeof (struct in_addr));
1877 }
1878
1879 u_short StrToPort (const char* str, const char* proto)
1880 {
1881         u_short         port;
1882         struct servent* sp;
1883         char*           end;
1884
1885         port = strtol (str, &end, 10);
1886         if (end != str)
1887                 return htons (port);
1888
1889         sp = getservbyname (str, proto);
1890         if (!sp)
1891                 errx (1, "%s/%s: unknown service", str, proto);
1892
1893         return sp->s_port;
1894 }
1895
1896 int StrToPortRange (const char* str, const char* proto, port_range *portRange)
1897 {
1898         const char*     sep;
1899         struct servent* sp;
1900         char*           end;
1901         u_short         loPort;
1902         u_short         hiPort;
1903         
1904         /* First see if this is a service, return corresponding port if so. */
1905         sp = getservbyname (str,proto);
1906         if (sp) {
1907                 SETLOPORT(*portRange, ntohs(sp->s_port));
1908                 SETNUMPORTS(*portRange, 1);
1909                 return 0;
1910         }
1911                 
1912         /* Not a service, see if it's a single port or port range. */
1913         sep = strchr (str, '-');
1914         if (sep == NULL) {
1915                 SETLOPORT(*portRange, strtol(str, &end, 10));
1916                 if (end != str) {
1917                         /* Single port. */
1918                         SETNUMPORTS(*portRange, 1);
1919                         return 0;
1920                 }
1921
1922                 /* Error in port range field. */
1923                 errx (1, "%s/%s: unknown service", str, proto);
1924         }
1925
1926         /* Port range, get the values and sanity check. */
1927         sscanf (str, "%hu-%hu", &loPort, &hiPort);
1928         SETLOPORT(*portRange, loPort);
1929         SETNUMPORTS(*portRange, 0);     /* Error by default */
1930         if (loPort <= hiPort)
1931                 SETNUMPORTS(*portRange, hiPort - loPort + 1);
1932
1933         if (GETNUMPORTS(*portRange) == 0)
1934                 errx (1, "invalid port range %s", str);
1935
1936         return 0;
1937 }
1938
1939
1940 static int
1941 StrToProto (const char* str)
1942 {
1943         if (!strcmp (str, "tcp"))
1944                 return IPPROTO_TCP;
1945
1946         if (!strcmp (str, "udp"))
1947                 return IPPROTO_UDP;
1948
1949         errx (1, "unknown protocol %s. Expected tcp or udp", str);
1950 }
1951
1952 static int
1953 StrToAddrAndPortRange (char* str, struct in_addr* addr, char* proto, port_range *portRange)
1954 {
1955         char*   ptr;
1956
1957         ptr = strchr (str, ':');
1958         if (!ptr)
1959                 errx (1, "%s is missing port number", str);
1960
1961         *ptr = '\0';
1962         ++ptr;
1963
1964         StrToAddr (str, addr);
1965         return StrToPortRange (ptr, proto, portRange);
1966 }
1967
1968 static void
1969 SetupPunchFW(const char *strValue)
1970 {
1971         unsigned int base, num;
1972
1973         if (sscanf(strValue, "%u:%u", &base, &num) != 2)
1974                 errx(1, "punch_fw: basenumber:count parameter required");
1975
1976         if (CheckIpfwRulenum(base + num - 1) == -1)
1977                 errx(1, "punch_fw: basenumber:count parameter should fit "
1978                         "the maximum allowed rule numbers");
1979
1980         LibAliasSetFWBase(mla, base, num);
1981         (void)LibAliasSetMode(mla, PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);
1982 }
1983
1984 static void
1985 SetupSkinnyPort(const char *strValue)
1986 {
1987         unsigned int port;
1988
1989         if (sscanf(strValue, "%u", &port) != 1)
1990                 errx(1, "skinny_port: port parameter required");
1991
1992         LibAliasSetSkinnyPort(mla, port);
1993 }
1994
1995 static void
1996 NewInstance(const char *name)
1997 {
1998         struct instance *ip;
1999
2000         LIST_FOREACH(ip, &root, list) {
2001                 if (!strcmp(ip->name, name)) {
2002                         mla = ip->la;
2003                         mip = ip;
2004                         return;
2005                 }
2006         }
2007         ninstance++;
2008         ip = calloc(1, sizeof(*ip));
2009         ip->name = strdup(name);
2010         ip->la = LibAliasInit (ip->la);
2011         ip->assignAliasAddr     = 0;
2012         ip->ifName              = NULL;
2013         ip->logDropped          = 0;
2014         ip->inPort              = 0;
2015         ip->outPort             = 0;
2016         ip->inOutPort           = 0;
2017         ip->aliasAddr.s_addr    = INADDR_NONE;
2018         ip->ifMTU               = -1;
2019         ip->aliasOverhead       = 12;
2020         LIST_INSERT_HEAD(&root, ip, list);
2021         mla = ip->la;
2022         mip = ip;
2023 }
2024
2025 static int
2026 CheckIpfwRulenum(unsigned int rnum)
2027 {
2028         unsigned int default_rule;
2029         size_t len = sizeof(default_rule);
2030
2031         if (sysctlbyname("net.inet.ip.fw.default_rule", &default_rule, &len,
2032                 NULL, 0) == -1) {
2033                 warn("Failed to get the default ipfw rule number, using "
2034                      "default historical value 65535.  The reason was");
2035                 default_rule = 65535;
2036         }
2037         if (rnum >= default_rule) {
2038                 return -1;
2039         }
2040
2041         return 0;
2042 }