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