]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/natd/natd.c
This commit was generated by cvs2svn to compensate for changes in r157043,
[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  const 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         socklen_t               addrSize;
503         struct ip*              ip;
504         char                    msgBuf[80];
505
506 /*
507  * Get packet from socket.
508  */
509         addrSize  = sizeof addr;
510         origBytes = recvfrom (fd,
511                               buf,
512                               sizeof buf,
513                               0,
514                               (struct sockaddr*) &addr,
515                               &addrSize);
516
517         if (origBytes == -1) {
518
519                 if (errno != EINTR)
520                         Warn ("read from divert socket failed");
521
522                 return;
523         }
524
525 #if 0
526         if (mip->assignAliasAddr) {
527                 SetAliasAddressFromIfName (mip->ifName);
528                 mip->assignAliasAddr = 0;
529         }
530 #endif
531 /*
532  * This is an IP packet.
533  */
534         ip = (struct ip*) buf;
535
536         if (verbose) {
537 /*
538  * Print packet direction and protocol type.
539  */
540                 printf ("Glb ");
541
542                 switch (ip->ip_p) {
543                 case IPPROTO_TCP:
544                         printf ("[TCP]  ");
545                         break;
546
547                 case IPPROTO_UDP:
548                         printf ("[UDP]  ");
549                         break;
550
551                 case IPPROTO_ICMP:
552                         printf ("[ICMP] ");
553                         break;
554
555                 default:
556                         printf ("[%d]    ", ip->ip_p);
557                         break;
558                 }
559 /*
560  * Print addresses.
561  */
562                 PrintPacket (ip);
563         }
564
565         LIST_FOREACH(mip, &root, list) {
566                 mla = mip->la;
567                 if (LibAliasOutTry (mla, buf, IP_MAXPACKET, 0) != PKT_ALIAS_IGNORED)
568                         break;
569         }
570 /*
571  * Length might have changed during aliasing.
572  */
573         bytes = ntohs (ip->ip_len);
574 /*
575  * Update alias overhead size for outgoing packets.
576  */
577         if (mip != NULL && bytes - origBytes > mip->aliasOverhead)
578                 mip->aliasOverhead = bytes - origBytes;
579
580         if (verbose) {
581                 
582 /*
583  * Print addresses after aliasing.
584  */
585                 printf (" aliased to\n");
586                 printf ("           ");
587                 PrintPacket (ip);
588                 printf ("\n");
589         }
590
591 /*
592  * Put packet back for processing.
593  */
594         wrote = sendto (fd, 
595                         buf,
596                         bytes,
597                         0,
598                         (struct sockaddr*) &addr,
599                         sizeof addr);
600         
601         if (wrote != bytes) {
602
603                 if (errno == EMSGSIZE) {
604
605                         if (mip->ifMTU != -1)
606                                 SendNeedFragIcmp (icmpSock,
607                                                   (struct ip*) buf,
608                                                   mip->ifMTU - mip->aliasOverhead);
609                 }
610                 else if (errno == EACCES && logIpfwDenied) {
611
612                         sprintf (msgBuf, "failed to write packet back");
613                         Warn (msgBuf);
614                 }
615         }
616 }
617
618
619 static void DoAliasing (int fd, int direction)
620 {
621         int                     bytes;
622         int                     origBytes;
623         char                    buf[IP_MAXPACKET];
624         struct sockaddr_in      addr;
625         int                     wrote;
626         int                     status;
627         socklen_t               addrSize;
628         struct ip*              ip;
629         char                    msgBuf[80];
630
631         if (mip->assignAliasAddr) {
632
633                 SetAliasAddressFromIfName (mip->ifName);
634                 mip->assignAliasAddr = 0;
635         }
636 /*
637  * Get packet from socket.
638  */
639         addrSize  = sizeof addr;
640         origBytes = recvfrom (fd,
641                               buf,
642                               sizeof buf,
643                               0,
644                               (struct sockaddr*) &addr,
645                               &addrSize);
646
647         if (origBytes == -1) {
648
649                 if (errno != EINTR)
650                         Warn ("read from divert socket failed");
651
652                 return;
653         }
654 /*
655  * This is an IP packet.
656  */
657         ip = (struct ip*) buf;
658         if (direction == DONT_KNOW) {
659                 if (addr.sin_addr.s_addr == INADDR_ANY)
660                         direction = OUTPUT;
661                 else
662                         direction = INPUT;
663         }
664
665         if (verbose) {
666 /*
667  * Print packet direction and protocol type.
668  */
669                 printf (direction == OUTPUT ? "Out " : "In  ");
670                 if (ninstance > 1)
671                         printf ("{%s}", mip->name);
672
673                 switch (ip->ip_p) {
674                 case IPPROTO_TCP:
675                         printf ("[TCP]  ");
676                         break;
677
678                 case IPPROTO_UDP:
679                         printf ("[UDP]  ");
680                         break;
681
682                 case IPPROTO_ICMP:
683                         printf ("[ICMP] ");
684                         break;
685
686                 default:
687                         printf ("[%d]    ", ip->ip_p);
688                         break;
689                 }
690 /*
691  * Print addresses.
692  */
693                 PrintPacket (ip);
694         }
695
696         if (direction == OUTPUT) {
697 /*
698  * Outgoing packets. Do aliasing.
699  */
700                 LibAliasOut (mla, buf, IP_MAXPACKET);
701         }
702         else {
703
704 /*
705  * Do aliasing.
706  */     
707                 status = LibAliasIn (mla, buf, IP_MAXPACKET);
708                 if (status == PKT_ALIAS_IGNORED &&
709                     mip->dropIgnoredIncoming) {
710
711                         if (verbose)
712                                 printf (" dropped.\n");
713
714                         if (mip->logDropped)
715                                 SyslogPacket (ip, LOG_WARNING, "denied");
716
717                         return;
718                 }
719         }
720 /*
721  * Length might have changed during aliasing.
722  */
723         bytes = ntohs (ip->ip_len);
724 /*
725  * Update alias overhead size for outgoing packets.
726  */
727         if (direction == OUTPUT &&
728             bytes - origBytes > mip->aliasOverhead)
729                 mip->aliasOverhead = bytes - origBytes;
730
731         if (verbose) {
732                 
733 /*
734  * Print addresses after aliasing.
735  */
736                 printf (" aliased to\n");
737                 printf ("           ");
738                 PrintPacket (ip);
739                 printf ("\n");
740         }
741
742 /*
743  * Put packet back for processing.
744  */
745         wrote = sendto (fd, 
746                         buf,
747                         bytes,
748                         0,
749                         (struct sockaddr*) &addr,
750                         sizeof addr);
751         
752         if (wrote != bytes) {
753
754                 if (errno == EMSGSIZE) {
755
756                         if (direction == OUTPUT &&
757                             mip->ifMTU != -1)
758                                 SendNeedFragIcmp (icmpSock,
759                                                   (struct ip*) buf,
760                                                   mip->ifMTU - mip->aliasOverhead);
761                 }
762                 else if (errno == EACCES && logIpfwDenied) {
763
764                         sprintf (msgBuf, "failed to write packet back");
765                         Warn (msgBuf);
766                 }
767         }
768 }
769
770 static void HandleRoutingInfo (int fd)
771 {
772         int                     bytes;
773         struct if_msghdr        ifMsg;
774 /*
775  * Get packet from socket.
776  */
777         bytes = read (fd, &ifMsg, sizeof ifMsg);
778         if (bytes == -1) {
779
780                 Warn ("read from routing socket failed");
781                 return;
782         }
783
784         if (ifMsg.ifm_version != RTM_VERSION) {
785
786                 Warn ("unexpected packet read from routing socket");
787                 return;
788         }
789
790         if (verbose)
791                 printf ("Routing message %#x received.\n", ifMsg.ifm_type);
792
793         if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO)) {
794                 LIST_FOREACH(mip, &root, list) {
795                         mla = mip->la;
796                         if (ifMsg.ifm_index == mip->ifIndex) {
797                                 if (verbose)
798                                         printf("Interface address/MTU has probably changed.\n");
799                                 mip->assignAliasAddr = 1;
800                         }
801                 }
802         }
803 }
804
805 static void PrintPacket (struct ip* ip)
806 {
807         printf ("%s", FormatPacket (ip));
808 }
809
810 static void SyslogPacket (struct ip* ip, int priority, const char *label)
811 {
812         syslog (priority, "%s %s", label, FormatPacket (ip));
813 }
814
815 static char* FormatPacket (struct ip* ip)
816 {
817         static char     buf[256];
818         struct tcphdr*  tcphdr;
819         struct udphdr*  udphdr;
820         struct icmp*    icmphdr;
821         char            src[20];
822         char            dst[20];
823
824         strcpy (src, inet_ntoa (ip->ip_src));
825         strcpy (dst, inet_ntoa (ip->ip_dst));
826
827         switch (ip->ip_p) {
828         case IPPROTO_TCP:
829                 tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2));
830                 sprintf (buf, "[TCP] %s:%d -> %s:%d",
831                               src,
832                               ntohs (tcphdr->th_sport),
833                               dst,
834                               ntohs (tcphdr->th_dport));
835                 break;
836
837         case IPPROTO_UDP:
838                 udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2));
839                 sprintf (buf, "[UDP] %s:%d -> %s:%d",
840                               src,
841                               ntohs (udphdr->uh_sport),
842                               dst,
843                               ntohs (udphdr->uh_dport));
844                 break;
845
846         case IPPROTO_ICMP:
847                 icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2));
848                 sprintf (buf, "[ICMP] %s -> %s %u(%u)",
849                               src,
850                               dst,
851                               icmphdr->icmp_type,
852                               icmphdr->icmp_code);
853                 break;
854
855         default:
856                 sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst);
857                 break;
858         }
859
860         return buf;
861 }
862
863 static void
864 SetAliasAddressFromIfName(const char *ifn)
865 {
866         size_t needed;
867         int mib[6];
868         char *buf, *lim, *next;
869         struct if_msghdr *ifm;
870         struct ifa_msghdr *ifam;
871         struct sockaddr_dl *sdl;
872         struct sockaddr_in *sin;
873
874         mib[0] = CTL_NET;
875         mib[1] = PF_ROUTE;
876         mib[2] = 0;
877         mib[3] = AF_INET;       /* Only IP addresses please */
878         mib[4] = NET_RT_IFLIST;
879         mib[5] = 0;             /* ifIndex??? */
880 /*
881  * Get interface data.
882  */
883         if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
884                 err(1, "iflist-sysctl-estimate");
885         if ((buf = malloc(needed)) == NULL)
886                 errx(1, "malloc failed");
887         if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
888                 err(1, "iflist-sysctl-get");
889         lim = buf + needed;
890 /*
891  * Loop through interfaces until one with
892  * given name is found. This is done to
893  * find correct interface index for routing
894  * message processing.
895  */
896         mip->ifIndex    = 0;
897         next = buf;
898         while (next < lim) {
899                 ifm = (struct if_msghdr *)next;
900                 next += ifm->ifm_msglen;
901                 if (ifm->ifm_version != RTM_VERSION) {
902                         if (verbose)
903                                 warnx("routing message version %d "
904                                       "not understood", ifm->ifm_version);
905                         continue;
906                 }
907                 if (ifm->ifm_type == RTM_IFINFO) {
908                         sdl = (struct sockaddr_dl *)(ifm + 1);
909                         if (strlen(ifn) == sdl->sdl_nlen &&
910                             strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) {
911                                 mip->ifIndex = ifm->ifm_index;
912                                 mip->ifMTU = ifm->ifm_data.ifi_mtu;
913                                 break;
914                         }
915                 }
916         }
917         if (!mip->ifIndex)
918                 errx(1, "unknown interface name %s", ifn);
919 /*
920  * Get interface address.
921  */
922         sin = NULL;
923         while (next < lim) {
924                 ifam = (struct ifa_msghdr *)next;
925                 next += ifam->ifam_msglen;
926                 if (ifam->ifam_version != RTM_VERSION) {
927                         if (verbose)
928                                 warnx("routing message version %d "
929                                       "not understood", ifam->ifam_version);
930                         continue;
931                 }
932                 if (ifam->ifam_type != RTM_NEWADDR)
933                         break;
934                 if (ifam->ifam_addrs & RTA_IFA) {
935                         int i;
936                         char *cp = (char *)(ifam + 1);
937
938                         for (i = 1; i < RTA_IFA; i <<= 1)
939                                 if (ifam->ifam_addrs & i)
940                                         cp += SA_SIZE((struct sockaddr *)cp);
941                         if (((struct sockaddr *)cp)->sa_family == AF_INET) {
942                                 sin = (struct sockaddr_in *)cp;
943                                 break;
944                         }
945                 }
946         }
947         if (sin == NULL)
948                 errx(1, "%s: cannot get interface address", ifn);
949
950         LibAliasSetAddress(mla, sin->sin_addr);
951         syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes",
952                inet_ntoa(sin->sin_addr), mip->ifMTU);
953
954         free(buf);
955 }
956
957 void Quit (const char* msg)
958 {
959         Warn (msg);
960         exit (1);
961 }
962
963 void Warn (const char* msg)
964 {
965         if (background)
966                 syslog (LOG_ALERT, "%s (%m)", msg);
967         else
968                 warn ("%s", msg);
969 }
970
971 static void RefreshAddr (int sig __unused)
972 {
973         if (mip->ifName)
974                 mip->assignAliasAddr = 1;
975 }
976
977 static void InitiateShutdown (int sig __unused)
978 {
979 /*
980  * Start timer to allow kernel gracefully
981  * shutdown existing connections when system
982  * is shut down.
983  */
984         siginterrupt(SIGALRM, 1);
985         signal (SIGALRM, Shutdown);
986         alarm (10);
987 }
988
989 static void Shutdown (int sig __unused)
990 {
991         running = 0;
992 }
993
994 /* 
995  * Different options recognized by this program.
996  */
997
998 enum Option {
999
1000         LibAliasOption,
1001         Instance,
1002         Verbose,
1003         InPort,
1004         OutPort,
1005         Port,
1006         GlobalPort,
1007         AliasAddress,
1008         TargetAddress,
1009         InterfaceName,
1010         RedirectPort,
1011         RedirectProto,
1012         RedirectAddress,
1013         ConfigFile,
1014         DynamicMode,
1015         ProxyRule,
1016         LogDenied,
1017         LogFacility,
1018         PunchFW,
1019         SkinnyPort,
1020         LogIpfwDenied,
1021         PidFile
1022 };
1023
1024 enum Param {
1025         
1026         YesNo,
1027         Numeric,
1028         String,
1029         None,
1030         Address,
1031         Service
1032 };
1033
1034 /*
1035  * Option information structure (used by ParseOption).
1036  */
1037
1038 struct OptionInfo {
1039         
1040         enum Option             type;
1041         int                     packetAliasOpt;
1042         enum Param              parm;
1043         const char*             parmDescription;
1044         const char*             description;
1045         const char*             name; 
1046         const char*             shortName;
1047 };
1048
1049 /*
1050  * Table of known options.
1051  */
1052
1053 static struct OptionInfo optionTable[] = {
1054
1055         { LibAliasOption,
1056                 PKT_ALIAS_UNREGISTERED_ONLY,
1057                 YesNo,
1058                 "[yes|no]",
1059                 "alias only unregistered addresses",
1060                 "unregistered_only",
1061                 "u" },
1062
1063         { LibAliasOption,
1064                 PKT_ALIAS_LOG,
1065                 YesNo,
1066                 "[yes|no]",
1067                 "enable logging",
1068                 "log",
1069                 "l" },
1070
1071         { LibAliasOption,
1072                 PKT_ALIAS_PROXY_ONLY,
1073                 YesNo,
1074                 "[yes|no]",
1075                 "proxy only",
1076                 "proxy_only",
1077                 NULL },
1078
1079         { LibAliasOption,
1080                 PKT_ALIAS_REVERSE,
1081                 YesNo,
1082                 "[yes|no]",
1083                 "operate in reverse mode",
1084                 "reverse",
1085                 NULL },
1086
1087         { LibAliasOption,
1088                 PKT_ALIAS_DENY_INCOMING,
1089                 YesNo,
1090                 "[yes|no]",
1091                 "allow incoming connections",
1092                 "deny_incoming",
1093                 "d" },
1094
1095         { LibAliasOption,
1096                 PKT_ALIAS_USE_SOCKETS,
1097                 YesNo,
1098                 "[yes|no]",
1099                 "use sockets to inhibit port conflict",
1100                 "use_sockets",
1101                 "s" },
1102
1103         { LibAliasOption,
1104                 PKT_ALIAS_SAME_PORTS,
1105                 YesNo,
1106                 "[yes|no]",
1107                 "try to keep original port numbers for connections",
1108                 "same_ports",
1109                 "m" },
1110
1111         { Verbose,
1112                 0,
1113                 YesNo,
1114                 "[yes|no]",
1115                 "verbose mode, dump packet information",
1116                 "verbose",
1117                 "v" },
1118         
1119         { DynamicMode,
1120                 0,
1121                 YesNo,
1122                 "[yes|no]",
1123                 "dynamic mode, automatically detect interface address changes",
1124                 "dynamic",
1125                 NULL },
1126         
1127         { InPort,
1128                 0,
1129                 Service,
1130                 "number|service_name",
1131                 "set port for incoming packets",
1132                 "in_port",
1133                 "i" },
1134         
1135         { OutPort,
1136                 0,
1137                 Service,
1138                 "number|service_name",
1139                 "set port for outgoing packets",
1140                 "out_port",
1141                 "o" },
1142         
1143         { Port,
1144                 0,
1145                 Service,
1146                 "number|service_name",
1147                 "set port (defaults to natd/divert)",
1148                 "port",
1149                 "p" },
1150         
1151         { GlobalPort,
1152                 0,
1153                 Service,
1154                 "number|service_name",
1155                 "set globalport",
1156                 "globalport",
1157                 NULL },
1158         
1159         { AliasAddress,
1160                 0,
1161                 Address,
1162                 "x.x.x.x",
1163                 "address to use for aliasing",
1164                 "alias_address",
1165                 "a" },
1166         
1167         { TargetAddress,
1168                 0,
1169                 Address,
1170                 "x.x.x.x",
1171                 "address to use for incoming sessions",
1172                 "target_address",
1173                 "t" },
1174         
1175         { InterfaceName,
1176                 0,
1177                 String,
1178                 "network_if_name",
1179                 "take aliasing address from interface",
1180                 "interface",
1181                 "n" },
1182
1183         { ProxyRule,
1184                 0,
1185                 String,
1186                 "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
1187                 "a.b.c.d:yyyy",
1188                 "add transparent proxying / destination NAT",
1189                 "proxy_rule",
1190                 NULL },
1191
1192         { RedirectPort,
1193                 0,
1194                 String,
1195                 "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
1196                 " [remote_addr[:remote_port_range]]",
1197                 "redirect a port (or ports) for incoming traffic",
1198                 "redirect_port",
1199                 NULL },
1200
1201         { RedirectProto,
1202                 0,
1203                 String,
1204                 "proto local_addr [public_addr] [remote_addr]",
1205                 "redirect packets of a given proto",
1206                 "redirect_proto",
1207                 NULL },
1208
1209         { RedirectAddress,
1210                 0,
1211                 String,
1212                 "local_addr[,...] public_addr",
1213                 "define mapping between local and public addresses",
1214                 "redirect_address",
1215                 NULL },
1216
1217         { ConfigFile,
1218                 0,
1219                 String,
1220                 "file_name",
1221                 "read options from configuration file",
1222                 "config",
1223                 "f" },
1224
1225         { LogDenied,
1226                 0,
1227                 YesNo,
1228                 "[yes|no]",
1229                 "enable logging of denied incoming packets",
1230                 "log_denied",
1231                 NULL },
1232
1233         { LogFacility,
1234                 0,
1235                 String,
1236                 "facility",
1237                 "name of syslog facility to use for logging",
1238                 "log_facility",
1239                 NULL },
1240
1241         { PunchFW,
1242                 0,
1243                 String,
1244                 "basenumber:count",
1245                 "punch holes in the firewall for incoming FTP/IRC DCC connections",
1246                 "punch_fw",
1247                 NULL },
1248
1249         { SkinnyPort,
1250                 0,
1251                 String,
1252                 "port",
1253                 "set the TCP port for use with the Skinny Station protocol",
1254                 "skinny_port",
1255                 NULL },
1256
1257         { LogIpfwDenied,
1258                 0,
1259                 YesNo,
1260                 "[yes|no]",
1261                 "log packets converted by natd, but denied by ipfw",
1262                 "log_ipfw_denied",
1263                 NULL },
1264
1265         { PidFile,
1266                 0,
1267                 String,
1268                 "file_name",
1269                 "store PID in an alternate file",
1270                 "pid_file",
1271                 "P" },
1272         { Instance,
1273                 0,
1274                 String,
1275                 "instance name",
1276                 "name of aliasing engine instance",
1277                 "instance",
1278                 NULL },
1279 };
1280         
1281 static void ParseOption (const char* option, const char* parms)
1282 {
1283         int                     i;
1284         struct OptionInfo*      info;
1285         int                     yesNoValue;
1286         int                     aliasValue;
1287         int                     numValue;
1288         u_short                 uNumValue;
1289         const char*             strValue;
1290         struct in_addr          addrValue;
1291         int                     max;
1292         char*                   end;
1293         CODE*                   fac_record = NULL;
1294 /*
1295  * Find option from table.
1296  */
1297         max = sizeof (optionTable) / sizeof (struct OptionInfo);
1298         for (i = 0, info = optionTable; i < max; i++, info++) {
1299
1300                 if (!strcmp (info->name, option))
1301                         break;
1302
1303                 if (info->shortName)
1304                         if (!strcmp (info->shortName, option))
1305                                 break;
1306         }
1307
1308         if (i >= max) {
1309
1310                 warnx ("unknown option %s", option);
1311                 Usage ();
1312         }
1313
1314         uNumValue       = 0;
1315         yesNoValue      = 0;
1316         numValue        = 0;
1317         strValue        = NULL;
1318 /*
1319  * Check parameters.
1320  */
1321         switch (info->parm) {
1322         case YesNo:
1323                 if (!parms)
1324                         parms = "yes";
1325
1326                 if (!strcmp (parms, "yes"))
1327                         yesNoValue = 1;
1328                 else
1329                         if (!strcmp (parms, "no"))
1330                                 yesNoValue = 0;
1331                         else
1332                                 errx (1, "%s needs yes/no parameter", option);
1333                 break;
1334
1335         case Service:
1336                 if (!parms)
1337                         errx (1, "%s needs service name or "
1338                                  "port number parameter",
1339                                  option);
1340
1341                 uNumValue = StrToPort (parms, "divert");
1342                 break;
1343
1344         case Numeric:
1345                 if (parms)
1346                         numValue = strtol (parms, &end, 10);
1347                 else
1348                         end = NULL;
1349
1350                 if (end == parms)
1351                         errx (1, "%s needs numeric parameter", option);
1352                 break;
1353
1354         case String:
1355                 strValue = parms;
1356                 if (!strValue)
1357                         errx (1, "%s needs parameter", option);
1358                 break;
1359
1360         case None:
1361                 if (parms)
1362                         errx (1, "%s does not take parameters", option);
1363                 break;
1364
1365         case Address:
1366                 if (!parms)
1367                         errx (1, "%s needs address/host parameter", option);
1368
1369                 StrToAddr (parms, &addrValue);
1370                 break;
1371         }
1372
1373         switch (info->type) {
1374         case LibAliasOption:
1375         
1376                 aliasValue = yesNoValue ? info->packetAliasOpt : 0;
1377                 LibAliasSetMode (mla, aliasValue, info->packetAliasOpt);
1378                 break;
1379
1380         case Verbose:
1381                 verbose = yesNoValue;
1382                 break;
1383
1384         case DynamicMode:
1385                 dynamicMode = yesNoValue;
1386                 break;
1387
1388         case InPort:
1389                 mip->inPort = uNumValue;
1390                 break;
1391
1392         case OutPort:
1393                 mip->outPort = uNumValue;
1394                 break;
1395
1396         case Port:
1397                 mip->inOutPort = uNumValue;
1398                 break;
1399
1400         case GlobalPort:
1401                 globalPort = uNumValue;
1402                 break;
1403
1404         case AliasAddress:
1405                 memcpy (&mip->aliasAddr, &addrValue, sizeof (struct in_addr));
1406                 break;
1407
1408         case TargetAddress:
1409                 LibAliasSetTarget(mla, addrValue);
1410                 break;
1411
1412         case RedirectPort:
1413                 SetupPortRedirect (strValue);
1414                 break;
1415
1416         case RedirectProto:
1417                 SetupProtoRedirect(strValue);
1418                 break;
1419
1420         case RedirectAddress:
1421                 SetupAddressRedirect (strValue);
1422                 break;
1423
1424         case ProxyRule:
1425                 LibAliasProxyRule (mla, strValue);
1426                 break;
1427
1428         case InterfaceName:
1429                 if (mip->ifName)
1430                         free (mip->ifName);
1431
1432                 mip->ifName = strdup (strValue);
1433                 break;
1434
1435         case ConfigFile:
1436                 ReadConfigFile (strValue);
1437                 break;
1438
1439         case LogDenied:
1440                 mip->logDropped = yesNoValue;
1441                 break;
1442
1443         case LogFacility:
1444
1445                 fac_record = facilitynames;
1446                 while (fac_record->c_name != NULL) {
1447
1448                         if (!strcmp (fac_record->c_name, strValue)) {
1449
1450                                 logFacility = fac_record->c_val;
1451                                 break;
1452
1453                         }
1454                         else
1455                                 fac_record++;
1456                 }
1457
1458                 if(fac_record->c_name == NULL)
1459                         errx(1, "Unknown log facility name: %s", strValue);     
1460
1461                 break;
1462
1463         case PunchFW:
1464                 SetupPunchFW(strValue);
1465                 break;
1466
1467         case SkinnyPort:
1468                 SetupSkinnyPort(strValue);
1469                 break;
1470
1471         case LogIpfwDenied:
1472                 logIpfwDenied = yesNoValue;;
1473                 break;
1474
1475         case PidFile:
1476                 pidName = strdup (strValue);
1477                 break;
1478         case Instance:
1479                 NewInstance(strValue);
1480                 break;
1481         }
1482 }
1483
1484 void ReadConfigFile (const char* fileName)
1485 {
1486         FILE*   file;
1487         char    *buf;
1488         size_t  len;
1489         char    *ptr, *p;
1490         char*   option;
1491
1492         file = fopen (fileName, "r");
1493         if (!file)
1494                 err(1, "cannot open config file %s", fileName);
1495
1496         while ((buf = fgetln(file, &len)) != NULL) {
1497                 if (buf[len - 1] == '\n')
1498                         buf[len - 1] = '\0';
1499                 else
1500                         errx(1, "config file format error: "
1501                                 "last line should end with newline");
1502
1503 /*
1504  * Check for comments, strip off trailing spaces.
1505  */
1506                 if ((ptr = strchr(buf, '#')))
1507                         *ptr = '\0';
1508                 for (ptr = buf; isspace(*ptr); ++ptr)
1509                         continue;
1510                 if (*ptr == '\0')
1511                         continue;
1512                 for (p = strchr(buf, '\0'); isspace(*--p);)
1513                         continue;
1514                 *++p = '\0';
1515
1516 /*
1517  * Extract option name.
1518  */
1519                 option = ptr;
1520                 while (*ptr && !isspace (*ptr))
1521                         ++ptr;
1522
1523                 if (*ptr != '\0') {
1524
1525                         *ptr = '\0';
1526                         ++ptr;
1527                 }
1528 /*
1529  * Skip white space between name and parms.
1530  */
1531                 while (*ptr && isspace (*ptr))
1532                         ++ptr;
1533
1534                 ParseOption (option, *ptr ? ptr : NULL);
1535         }
1536
1537         fclose (file);
1538 }
1539
1540 static void Usage ()
1541 {
1542         int                     i;
1543         int                     max;
1544         struct OptionInfo*      info;
1545
1546         fprintf (stderr, "Recognized options:\n\n");
1547
1548         max = sizeof (optionTable) / sizeof (struct OptionInfo);
1549         for (i = 0, info = optionTable; i < max; i++, info++) {
1550
1551                 fprintf (stderr, "-%-20s %s\n", info->name,
1552                                                 info->parmDescription);
1553
1554                 if (info->shortName)
1555                         fprintf (stderr, "-%-20s %s\n", info->shortName,
1556                                                         info->parmDescription);
1557
1558                 fprintf (stderr, "      %s\n\n", info->description);
1559         }
1560
1561         exit (1);
1562 }
1563
1564 void SetupPortRedirect (const char* parms)
1565 {
1566         char            buf[128];
1567         char*           ptr;
1568         char*           serverPool;
1569         struct in_addr  localAddr;
1570         struct in_addr  publicAddr;
1571         struct in_addr  remoteAddr;
1572         port_range      portRange;
1573         u_short         localPort      = 0;
1574         u_short         publicPort     = 0;
1575         u_short         remotePort     = 0;
1576         u_short         numLocalPorts  = 0;
1577         u_short         numPublicPorts = 0;
1578         u_short         numRemotePorts = 0;
1579         int             proto;
1580         char*           protoName;
1581         char*           separator;
1582         int             i;
1583         struct alias_link *aliaslink = NULL;
1584
1585         strlcpy (buf, parms, sizeof(buf));
1586 /*
1587  * Extract protocol.
1588  */
1589         protoName = strtok (buf, " \t");
1590         if (!protoName)
1591                 errx (1, "redirect_port: missing protocol");
1592
1593         proto = StrToProto (protoName);
1594 /*
1595  * Extract local address.
1596  */
1597         ptr = strtok (NULL, " \t");
1598         if (!ptr)
1599                 errx (1, "redirect_port: missing local address");
1600
1601         separator = strchr(ptr, ',');
1602         if (separator) {                /* LSNAT redirection syntax. */
1603                 localAddr.s_addr = INADDR_NONE;
1604                 localPort = ~0;
1605                 numLocalPorts = 1;
1606                 serverPool = ptr;
1607         } else {
1608                 if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 )
1609                         errx (1, "redirect_port: invalid local port range");
1610
1611                 localPort     = GETLOPORT(portRange);
1612                 numLocalPorts = GETNUMPORTS(portRange);
1613                 serverPool = NULL;
1614         }
1615
1616 /*
1617  * Extract public port and optionally address.
1618  */
1619         ptr = strtok (NULL, " \t");
1620         if (!ptr)
1621                 errx (1, "redirect_port: missing public port");
1622
1623         separator = strchr (ptr, ':');
1624         if (separator) {
1625                 if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 )
1626                         errx (1, "redirect_port: invalid public port range");
1627         }
1628         else {
1629                 publicAddr.s_addr = INADDR_ANY;
1630                 if (StrToPortRange (ptr, protoName, &portRange) != 0)
1631                         errx (1, "redirect_port: invalid public port range");
1632         }
1633
1634         publicPort     = GETLOPORT(portRange);
1635         numPublicPorts = GETNUMPORTS(portRange);
1636
1637 /*
1638  * Extract remote address and optionally port.
1639  */
1640         ptr = strtok (NULL, " \t");
1641         if (ptr) {
1642                 separator = strchr (ptr, ':');
1643                 if (separator) {
1644                         if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0)
1645                                 errx (1, "redirect_port: invalid remote port range");
1646                 } else {
1647                         SETLOPORT(portRange, 0);
1648                         SETNUMPORTS(portRange, 1);
1649                         StrToAddr (ptr, &remoteAddr);
1650                 }
1651         }
1652         else {
1653                 SETLOPORT(portRange, 0);
1654                 SETNUMPORTS(portRange, 1);
1655                 remoteAddr.s_addr = INADDR_ANY;
1656         }
1657
1658         remotePort     = GETLOPORT(portRange);
1659         numRemotePorts = GETNUMPORTS(portRange);
1660
1661 /*
1662  * Make sure port ranges match up, then add the redirect ports.
1663  */
1664         if (numLocalPorts != numPublicPorts)
1665                 errx (1, "redirect_port: port ranges must be equal in size");
1666
1667         /* Remote port range is allowed to be '0' which means all ports. */
1668         if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0))
1669                 errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
1670
1671         for (i = 0 ; i < numPublicPorts ; ++i) {
1672                 /* If remotePort is all ports, set it to 0. */
1673                 u_short remotePortCopy = remotePort + i;
1674                 if (numRemotePorts == 1 && remotePort == 0)
1675                         remotePortCopy = 0;
1676
1677                 aliaslink = LibAliasRedirectPort (mla, localAddr,
1678                                                 htons(localPort + i),
1679                                                 remoteAddr,
1680                                                 htons(remotePortCopy),
1681                                                 publicAddr,
1682                                                 htons(publicPort + i),
1683                                                 proto);
1684         }
1685
1686 /*
1687  * Setup LSNAT server pool.
1688  */
1689         if (serverPool != NULL && aliaslink != NULL) {
1690                 ptr = strtok(serverPool, ",");
1691                 while (ptr != NULL) {
1692                         if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0)
1693                                 errx(1, "redirect_port: invalid local port range");
1694
1695                         localPort = GETLOPORT(portRange);
1696                         if (GETNUMPORTS(portRange) != 1)
1697                                 errx(1, "redirect_port: local port must be single in this context");
1698                         LibAliasAddServer(mla, aliaslink, localAddr, htons(localPort));
1699                         ptr = strtok(NULL, ",");
1700                 }
1701         }
1702 }
1703
1704 void
1705 SetupProtoRedirect(const char* parms)
1706 {
1707         char            buf[128];
1708         char*           ptr;
1709         struct in_addr  localAddr;
1710         struct in_addr  publicAddr;
1711         struct in_addr  remoteAddr;
1712         int             proto;
1713         char*           protoName;
1714         struct protoent *protoent;
1715
1716         strlcpy (buf, parms, sizeof(buf));
1717 /*
1718  * Extract protocol.
1719  */
1720         protoName = strtok(buf, " \t");
1721         if (!protoName)
1722                 errx(1, "redirect_proto: missing protocol");
1723
1724         protoent = getprotobyname(protoName);
1725         if (protoent == NULL)
1726                 errx(1, "redirect_proto: unknown protocol %s", protoName);
1727         else
1728                 proto = protoent->p_proto;
1729 /*
1730  * Extract local address.
1731  */
1732         ptr = strtok(NULL, " \t");
1733         if (!ptr)
1734                 errx(1, "redirect_proto: missing local address");
1735         else
1736                 StrToAddr(ptr, &localAddr);
1737 /*
1738  * Extract optional public address.
1739  */
1740         ptr = strtok(NULL, " \t");
1741         if (ptr)
1742                 StrToAddr(ptr, &publicAddr);
1743         else
1744                 publicAddr.s_addr = INADDR_ANY;
1745 /*
1746  * Extract optional remote address.
1747  */
1748         ptr = strtok(NULL, " \t");
1749         if (ptr)
1750                 StrToAddr(ptr, &remoteAddr);
1751         else
1752                 remoteAddr.s_addr = INADDR_ANY;
1753 /*
1754  * Create aliasing link.
1755  */
1756         (void)LibAliasRedirectProto(mla, localAddr, remoteAddr, publicAddr,
1757                                        proto);
1758 }
1759
1760 void SetupAddressRedirect (const char* parms)
1761 {
1762         char            buf[128];
1763         char*           ptr;
1764         char*           separator;
1765         struct in_addr  localAddr;
1766         struct in_addr  publicAddr;
1767         char*           serverPool;
1768         struct alias_link *aliaslink;
1769
1770         strlcpy (buf, parms, sizeof(buf));
1771 /*
1772  * Extract local address.
1773  */
1774         ptr = strtok (buf, " \t");
1775         if (!ptr)
1776                 errx (1, "redirect_address: missing local address");
1777
1778         separator = strchr(ptr, ',');
1779         if (separator) {                /* LSNAT redirection syntax. */
1780                 localAddr.s_addr = INADDR_NONE;
1781                 serverPool = ptr;
1782         } else {
1783                 StrToAddr (ptr, &localAddr);
1784                 serverPool = NULL;
1785         }
1786 /*
1787  * Extract public address.
1788  */
1789         ptr = strtok (NULL, " \t");
1790         if (!ptr)
1791                 errx (1, "redirect_address: missing public address");
1792
1793         StrToAddr (ptr, &publicAddr);
1794         aliaslink = LibAliasRedirectAddr(mla, localAddr, publicAddr);
1795
1796 /*
1797  * Setup LSNAT server pool.
1798  */
1799         if (serverPool != NULL && aliaslink != NULL) {
1800                 ptr = strtok(serverPool, ",");
1801                 while (ptr != NULL) {
1802                         StrToAddr(ptr, &localAddr);
1803                         LibAliasAddServer(mla, aliaslink, localAddr, htons(~0));
1804                         ptr = strtok(NULL, ",");
1805                 }
1806         }
1807 }
1808
1809 void StrToAddr (const char* str, struct in_addr* addr)
1810 {
1811         struct hostent* hp;
1812
1813         if (inet_aton (str, addr))
1814                 return;
1815
1816         hp = gethostbyname (str);
1817         if (!hp)
1818                 errx (1, "unknown host %s", str);
1819
1820         memcpy (addr, hp->h_addr, sizeof (struct in_addr));
1821 }
1822
1823 u_short StrToPort (const char* str, const char* proto)
1824 {
1825         u_short         port;
1826         struct servent* sp;
1827         char*           end;
1828
1829         port = strtol (str, &end, 10);
1830         if (end != str)
1831                 return htons (port);
1832
1833         sp = getservbyname (str, proto);
1834         if (!sp)
1835                 errx (1, "%s/%s: unknown service", str, proto);
1836
1837         return sp->s_port;
1838 }
1839
1840 int StrToPortRange (const char* str, const char* proto, port_range *portRange)
1841 {
1842         char*           sep;
1843         struct servent* sp;
1844         char*           end;
1845         u_short         loPort;
1846         u_short         hiPort;
1847         
1848         /* First see if this is a service, return corresponding port if so. */
1849         sp = getservbyname (str,proto);
1850         if (sp) {
1851                 SETLOPORT(*portRange, ntohs(sp->s_port));
1852                 SETNUMPORTS(*portRange, 1);
1853                 return 0;
1854         }
1855                 
1856         /* Not a service, see if it's a single port or port range. */
1857         sep = strchr (str, '-');
1858         if (sep == NULL) {
1859                 SETLOPORT(*portRange, strtol(str, &end, 10));
1860                 if (end != str) {
1861                         /* Single port. */
1862                         SETNUMPORTS(*portRange, 1);
1863                         return 0;
1864                 }
1865
1866                 /* Error in port range field. */
1867                 errx (1, "%s/%s: unknown service", str, proto);
1868         }
1869
1870         /* Port range, get the values and sanity check. */
1871         sscanf (str, "%hu-%hu", &loPort, &hiPort);
1872         SETLOPORT(*portRange, loPort);
1873         SETNUMPORTS(*portRange, 0);     /* Error by default */
1874         if (loPort <= hiPort)
1875                 SETNUMPORTS(*portRange, hiPort - loPort + 1);
1876
1877         if (GETNUMPORTS(*portRange) == 0)
1878                 errx (1, "invalid port range %s", str);
1879
1880         return 0;
1881 }
1882
1883
1884 int StrToProto (const char* str)
1885 {
1886         if (!strcmp (str, "tcp"))
1887                 return IPPROTO_TCP;
1888
1889         if (!strcmp (str, "udp"))
1890                 return IPPROTO_UDP;
1891
1892         errx (1, "unknown protocol %s. Expected tcp or udp", str);
1893 }
1894
1895 int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange)
1896 {
1897         char*   ptr;
1898
1899         ptr = strchr (str, ':');
1900         if (!ptr)
1901                 errx (1, "%s is missing port number", str);
1902
1903         *ptr = '\0';
1904         ++ptr;
1905
1906         StrToAddr (str, addr);
1907         return StrToPortRange (ptr, proto, portRange);
1908 }
1909
1910 static void
1911 SetupPunchFW(const char *strValue)
1912 {
1913         unsigned int base, num;
1914
1915         if (sscanf(strValue, "%u:%u", &base, &num) != 2)
1916                 errx(1, "punch_fw: basenumber:count parameter required");
1917
1918         LibAliasSetFWBase(mla, base, num);
1919         (void)LibAliasSetMode(mla, PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);
1920 }
1921
1922 static void
1923 SetupSkinnyPort(const char *strValue)
1924 {
1925         unsigned int port;
1926
1927         if (sscanf(strValue, "%u", &port) != 1)
1928                 errx(1, "skinny_port: port parameter required");
1929
1930         LibAliasSetSkinnyPort(mla, port);
1931 }
1932
1933 static void
1934 NewInstance(const char *name)
1935 {
1936         struct instance *ip;
1937
1938         LIST_FOREACH(ip, &root, list) {
1939                 if (!strcmp(ip->name, name)) {
1940                         mla = ip->la;
1941                         mip = ip;
1942                         return;
1943                 }
1944         }
1945         ninstance++;
1946         ip = calloc(sizeof *ip, 1);
1947         ip->name = strdup(name);
1948         ip->la = LibAliasInit (ip->la);
1949         ip->assignAliasAddr     = 0;
1950         ip->ifName              = NULL;
1951         ip->logDropped          = 0;
1952         ip->inPort              = 0;
1953         ip->outPort             = 0;
1954         ip->inOutPort           = 0;
1955         ip->aliasAddr.s_addr    = INADDR_NONE;
1956         ip->ifMTU               = -1;
1957         ip->aliasOverhead       = 12;
1958         LIST_INSERT_HEAD(&root, ip, list);
1959         mla = ip->la;
1960         mip = ip;
1961 }