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