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