]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sbin/natd/natd.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sbin / natd / natd.c
1 /*
2  * natd - Network Address Translation Daemon for FreeBSD.
3  *
4  * This software is provided free of charge, with no 
5  * warranty of any kind, either expressed or implied.
6  * Use at your own risk.
7  * 
8  * You may copy, modify and distribute this software (natd.c) freely.
9  *
10  * Ari Suutari <suutari@iki.fi>
11  */
12
13 #include <sys/cdefs.h>
14 __FBSDID("$FreeBSD$");
15
16 #define SYSLOG_NAMES
17
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <sys/sysctl.h>
21 #include <sys/time.h>
22 #include <sys/queue.h>
23
24 #include <netinet/in.h>
25 #include <netinet/in_systm.h>
26 #include <netinet/ip.h>
27 #include <machine/in_cksum.h>
28 #include <netinet/tcp.h>
29 #include <netinet/udp.h>
30 #include <netinet/ip_icmp.h>
31 #include <net/if.h>
32 #include <net/if_dl.h>
33 #include <net/route.h>
34 #include <arpa/inet.h>
35
36 #include <alias.h>
37 #include <ctype.h>
38 #include <err.h>
39 #include <errno.h>
40 #include <netdb.h>
41 #include <signal.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <syslog.h>
46 #include <unistd.h>
47
48 #include "natd.h"
49
50 struct instance {
51         const char              *name;
52         struct libalias         *la;
53         LIST_ENTRY(instance)    list;
54
55         int                     ifIndex;
56         int                     assignAliasAddr;
57         char*                   ifName;
58         int                     logDropped;
59         u_short                 inPort;
60         u_short                 outPort;
61         u_short                 inOutPort;
62         struct in_addr          aliasAddr;
63         int                     ifMTU;
64         int                     aliasOverhead;
65         int                     dropIgnoredIncoming;
66         int                     divertIn;
67         int                     divertOut;
68         int                     divertInOut;
69 };
70
71 static LIST_HEAD(, instance) root = LIST_HEAD_INITIALIZER(&root);
72
73 struct libalias *mla;
74 struct instance *mip;
75 int ninstance = 1;
76
77 /* 
78  * Default values for input and output
79  * divert socket ports.
80  */
81
82 #define DEFAULT_SERVICE "natd"
83
84 /*
85  * Definition of a port range, and macros to deal with values.
86  * FORMAT:  HI 16-bits == first port in range, 0 == all ports.
87  *          LO 16-bits == number of ports in range
88  * NOTES:   - Port values are not stored in network byte order.
89  */
90
91 typedef u_long port_range;
92
93 #define GETLOPORT(x)     ((x) >> 0x10)
94 #define GETNUMPORTS(x)   ((x) & 0x0000ffff)
95 #define GETHIPORT(x)     (GETLOPORT((x)) + GETNUMPORTS((x)))
96
97 /* Set y to be the low-port value in port_range variable x. */
98 #define SETLOPORT(x,y)   ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
99
100 /* Set y to be the number of ports in port_range variable x. */
101 #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y))
102
103 /*
104  * Function prototypes.
105  */
106
107 static void     DoAliasing (int fd, int direction);
108 static void     DaemonMode (void);
109 static void     HandleRoutingInfo (int fd);
110 static void     Usage (void);
111 static char*    FormatPacket (struct ip*);
112 static void     PrintPacket (struct ip*);
113 static void     SyslogPacket (struct ip*, int priority, const char *label);
114 static void     SetAliasAddressFromIfName (const char *ifName);
115 static void     InitiateShutdown (int);
116 static void     Shutdown (int);
117 static void     RefreshAddr (int);
118 static void     ParseOption (const char* option, const char* parms);
119 static void     ReadConfigFile (const char* fileName);
120 static void     SetupPortRedirect (const char* parms);
121 static void     SetupProtoRedirect(const char* parms);
122 static void     SetupAddressRedirect (const char* parms);
123 static void     StrToAddr (const char* str, struct in_addr* addr);
124 static u_short  StrToPort (const char* str, const char* proto);
125 static int      StrToPortRange (const char* str, const char* proto, port_range *portRange);
126 static int      StrToProto (const char* str);
127 static int      StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange);
128 static void     ParseArgs (int argc, char** argv);
129 static void     SetupPunchFW(const char *strValue);
130 static void     SetupSkinnyPort(const char *strValue);
131 static void     NewInstance(const char *name);
132 static void     DoGlobal (int fd);
133 static int      CheckIpfwRulenum(unsigned int rnum);
134
135 /*
136  * Globals.
137  */
138
139 static  int                     verbose;
140 static  int                     background;
141 static  int                     running;
142 static  int                     logFacility;
143
144 static  int                     dynamicMode;
145 static  int                     icmpSock;
146 static  int                     logIpfwDenied;
147 static  const char*             pidName;
148 static  int                     routeSock;
149 static  int                     globalPort;
150 static  int                     divertGlobal;
151
152 int main (int argc, char** argv)
153 {
154         struct sockaddr_in      addr;
155         fd_set                  readMask;
156         int                     fdMax;
157 /* 
158  * Initialize packet aliasing software.
159  * Done already here to be able to alter option bits
160  * during command line and configuration file processing.
161  */
162         NewInstance("default");
163
164 /*
165  * Parse options.
166  */
167         verbose                 = 0;
168         background              = 0;
169         running                 = 1;
170         dynamicMode             = 0;
171         logFacility             = LOG_DAEMON;
172         logIpfwDenied           = -1;
173         pidName                 = PIDFILE;
174         routeSock               = -1;
175         icmpSock                = -1;
176         fdMax                   = -1;
177         divertGlobal            = -1;
178
179         ParseArgs (argc, argv);
180 /*
181  * Log ipfw(8) denied packets by default in verbose mode.
182  */
183         if (logIpfwDenied == -1)
184                 logIpfwDenied = verbose;
185 /*
186  * Open syslog channel.
187  */
188         openlog ("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0),
189                  logFacility);
190
191         LIST_FOREACH(mip, &root, list) {
192                 mla = mip->la;
193 /*
194  * If not doing the transparent proxying only,
195  * check that valid aliasing address has been given.
196  */
197                 if (mip->aliasAddr.s_addr == INADDR_NONE && mip->ifName == NULL &&
198                     !(LibAliasSetMode(mla, 0,0) & PKT_ALIAS_PROXY_ONLY))
199                         errx (1, "instance %s: aliasing address not given", mip->name);
200
201                 if (mip->aliasAddr.s_addr != INADDR_NONE && mip->ifName != NULL)
202                         errx (1, "both alias address and interface "
203                                  "name are not allowed");
204 /*
205  * Check that valid port number is known.
206  */
207                 if (mip->inPort != 0 || mip->outPort != 0)
208                         if (mip->inPort == 0 || mip->outPort == 0)
209                                 errx (1, "both input and output ports are required");
210
211                 if (mip->inPort == 0 && mip->outPort == 0 && mip->inOutPort == 0)
212                         ParseOption ("port", DEFAULT_SERVICE);
213
214 /*
215  * Check if ignored packets should be dropped.
216  */
217                 mip->dropIgnoredIncoming = LibAliasSetMode (mla, 0, 0);
218                 mip->dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING;
219 /*
220  * Create divert sockets. Use only one socket if -p was specified
221  * on command line. Otherwise, create separate sockets for
222  * outgoing and incoming connnections.
223  */
224                 if (mip->inOutPort) {
225
226                         mip->divertInOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
227                         if (mip->divertInOut == -1)
228                                 Quit ("Unable to create divert socket.");
229                         if (mip->divertInOut > fdMax)
230                                 fdMax = mip->divertInOut;
231
232                         mip->divertIn  = -1;
233                         mip->divertOut = -1;
234 /*
235  * Bind socket.
236  */
237
238                         addr.sin_family         = AF_INET;
239                         addr.sin_addr.s_addr    = INADDR_ANY;
240                         addr.sin_port           = mip->inOutPort;
241
242                         if (bind (mip->divertInOut,
243                                   (struct sockaddr*) &addr,
244                                   sizeof addr) == -1)
245                                 Quit ("Unable to bind divert socket.");
246                 }
247                 else {
248
249                         mip->divertIn = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
250                         if (mip->divertIn == -1)
251                                 Quit ("Unable to create incoming divert socket.");
252                         if (mip->divertIn > fdMax)
253                                 fdMax = mip->divertIn;
254
255
256                         mip->divertOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
257                         if (mip->divertOut == -1)
258                                 Quit ("Unable to create outgoing divert socket.");
259                         if (mip->divertOut > fdMax)
260                                 fdMax = mip->divertOut;
261
262                         mip->divertInOut = -1;
263
264 /*
265  * Bind divert sockets.
266  */
267
268                         addr.sin_family         = AF_INET;
269                         addr.sin_addr.s_addr    = INADDR_ANY;
270                         addr.sin_port           = mip->inPort;
271
272                         if (bind (mip->divertIn,
273                                   (struct sockaddr*) &addr,
274                                   sizeof addr) == -1)
275                                 Quit ("Unable to bind incoming divert socket.");
276
277                         addr.sin_family         = AF_INET;
278                         addr.sin_addr.s_addr    = INADDR_ANY;
279                         addr.sin_port           = mip->outPort;
280
281                         if (bind (mip->divertOut,
282                                   (struct sockaddr*) &addr,
283                                   sizeof addr) == -1)
284                                 Quit ("Unable to bind outgoing divert socket.");
285                 }
286 /*
287  * Create routing socket if interface name specified and in dynamic mode.
288  */
289                 if (mip->ifName) {
290                         if (dynamicMode) {
291
292                                 if (routeSock == -1)
293                                         routeSock = socket (PF_ROUTE, SOCK_RAW, 0);
294                                 if (routeSock == -1)
295                                         Quit ("Unable to create routing info socket.");
296                                 if (routeSock > fdMax)
297                                         fdMax = routeSock;
298
299                                 mip->assignAliasAddr = 1;
300                         }
301                         else
302                                 SetAliasAddressFromIfName (mip->ifName);
303                 }
304
305         }
306         if (globalPort) {
307
308                 divertGlobal = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
309                 if (divertGlobal == -1)
310                         Quit ("Unable to create divert socket.");
311                 if (divertGlobal > fdMax)
312                         fdMax = divertGlobal;
313
314 /*
315 * Bind socket.
316 */
317
318                 addr.sin_family         = AF_INET;
319                 addr.sin_addr.s_addr    = INADDR_ANY;
320                 addr.sin_port           = globalPort;
321
322                 if (bind (divertGlobal,
323                           (struct sockaddr*) &addr,
324                           sizeof addr) == -1)
325                         Quit ("Unable to bind global divert socket.");
326         }
327 /*
328  * Create socket for sending ICMP messages.
329  */
330         icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
331         if (icmpSock == -1)
332                 Quit ("Unable to create ICMP socket.");
333
334 /*
335  * And disable reads for the socket, otherwise it slowly fills
336  * up with received icmps which we do not use.
337  */
338         shutdown(icmpSock, SHUT_RD);
339
340 /*
341  * Become a daemon unless verbose mode was requested.
342  */
343         if (!verbose)
344                 DaemonMode ();
345 /*
346  * Catch signals to manage shutdown and
347  * refresh of interface address.
348  */
349         siginterrupt(SIGTERM, 1);
350         siginterrupt(SIGHUP, 1);
351         signal (SIGTERM, InitiateShutdown);
352         signal (SIGHUP, RefreshAddr);
353 /*
354  * Set alias address if it has been given.
355  */
356         mip = LIST_FIRST(&root);        /* XXX: simon */
357         LIST_FOREACH(mip, &root, list) {
358                 mla = mip->la;
359                 if (mip->aliasAddr.s_addr != INADDR_NONE)
360                         LibAliasSetAddress (mla, mip->aliasAddr);
361         }
362
363         while (running) {
364                 mip = LIST_FIRST(&root);        /* XXX: simon */
365
366                 if (mip->divertInOut != -1 && !mip->ifName && ninstance == 1) {
367 /*
368  * When using only one socket, just call 
369  * DoAliasing repeatedly to process packets.
370  */
371                         DoAliasing (mip->divertInOut, DONT_KNOW);
372                         continue;
373                 }
374 /* 
375  * Build read mask from socket descriptors to select.
376  */
377                 FD_ZERO (&readMask);
378 /*
379  * Check if new packets are available.
380  */
381                 LIST_FOREACH(mip, &root, list) {
382                         if (mip->divertIn != -1)
383                                 FD_SET (mip->divertIn, &readMask);
384
385                         if (mip->divertOut != -1)
386                                 FD_SET (mip->divertOut, &readMask);
387
388                         if (mip->divertInOut != -1)
389                                 FD_SET (mip->divertInOut, &readMask);
390                 }
391 /*
392  * Routing info is processed always.
393  */
394                 if (routeSock != -1)
395                         FD_SET (routeSock, &readMask);
396
397                 if (divertGlobal != -1)
398                         FD_SET (divertGlobal, &readMask);
399
400                 if (select (fdMax + 1,
401                             &readMask,
402                             NULL,
403                             NULL,
404                             NULL) == -1) {
405
406                         if (errno == EINTR)
407                                 continue;
408
409                         Quit ("Select failed.");
410                 }
411
412                 if (divertGlobal != -1)
413                         if (FD_ISSET (divertGlobal, &readMask))
414                                 DoGlobal (divertGlobal);
415                 LIST_FOREACH(mip, &root, list) {
416                         mla = mip->la;
417                         if (mip->divertIn != -1)
418                                 if (FD_ISSET (mip->divertIn, &readMask))
419                                         DoAliasing (mip->divertIn, INPUT);
420
421                         if (mip->divertOut != -1)
422                                 if (FD_ISSET (mip->divertOut, &readMask))
423                                         DoAliasing (mip->divertOut, OUTPUT);
424
425                         if (mip->divertInOut != -1) 
426                                 if (FD_ISSET (mip->divertInOut, &readMask))
427                                         DoAliasing (mip->divertInOut, DONT_KNOW);
428
429                 }
430                 if (routeSock != -1)
431                         if (FD_ISSET (routeSock, &readMask))
432                                 HandleRoutingInfo (routeSock);
433         }
434
435         if (background)
436                 unlink (pidName);
437
438         return 0;
439 }
440
441 static void DaemonMode ()
442 {
443         FILE*   pidFile;
444
445         daemon (0, 0);
446         background = 1;
447
448         pidFile = fopen (pidName, "w");
449         if (pidFile) {
450
451                 fprintf (pidFile, "%d\n", getpid ());
452                 fclose (pidFile);
453         }
454 }
455
456 static void ParseArgs (int argc, char** argv)
457 {
458         int             arg;
459         char*           opt;
460         char            parmBuf[256];
461         int             len; /* bounds checking */
462
463         for (arg = 1; arg < argc; arg++) {
464
465                 opt  = argv[arg];
466                 if (*opt != '-') {
467
468                         warnx ("invalid option %s", opt);
469                         Usage ();
470                 }
471
472                 parmBuf[0] = '\0';
473                 len = 0;
474
475                 while (arg < argc - 1) {
476
477                         if (argv[arg + 1][0] == '-')
478                                 break;
479
480                         if (len) {
481                                 strncat (parmBuf, " ", sizeof(parmBuf) - (len + 1));
482                                 len += strlen(parmBuf + len);
483                         }
484
485                         ++arg;
486                         strncat (parmBuf, argv[arg], sizeof(parmBuf) - (len + 1));
487                         len += strlen(parmBuf + len);
488
489                 }
490
491                 ParseOption (opt + 1, (len ? parmBuf : NULL));
492
493         }
494 }
495
496 static void DoGlobal (int fd)
497 {
498         int                     bytes;
499         int                     origBytes;
500         char                    buf[IP_MAXPACKET];
501         struct sockaddr_in      addr;
502         int                     wrote;
503         socklen_t               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         socklen_t               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}", 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 __unused)
973 {
974         LibAliasRefreshModules();
975         if (mip != NULL && mip->ifName != NULL)
976                 mip->assignAliasAddr = 1;
977 }
978
979 static void InitiateShutdown (int sig __unused)
980 {
981 /*
982  * Start timer to allow kernel gracefully
983  * shutdown existing connections when system
984  * is shut down.
985  */
986         siginterrupt(SIGALRM, 1);
987         signal (SIGALRM, Shutdown);
988         alarm (10);
989 }
990
991 static void Shutdown (int sig __unused)
992 {
993         running = 0;
994 }
995
996 /* 
997  * Different options recognized by this program.
998  */
999
1000 enum Option {
1001
1002         LibAliasOption,
1003         Instance,
1004         Verbose,
1005         InPort,
1006         OutPort,
1007         Port,
1008         GlobalPort,
1009         AliasAddress,
1010         TargetAddress,
1011         InterfaceName,
1012         RedirectPort,
1013         RedirectProto,
1014         RedirectAddress,
1015         ConfigFile,
1016         DynamicMode,
1017         ProxyRule,
1018         LogDenied,
1019         LogFacility,
1020         PunchFW,
1021         SkinnyPort,
1022         LogIpfwDenied,
1023         PidFile
1024 };
1025
1026 enum Param {
1027         
1028         YesNo,
1029         Numeric,
1030         String,
1031         None,
1032         Address,
1033         Service
1034 };
1035
1036 /*
1037  * Option information structure (used by ParseOption).
1038  */
1039
1040 struct OptionInfo {
1041         
1042         enum Option             type;
1043         int                     packetAliasOpt;
1044         enum Param              parm;
1045         const char*             parmDescription;
1046         const char*             description;
1047         const char*             name; 
1048         const char*             shortName;
1049 };
1050
1051 /*
1052  * Table of known options.
1053  */
1054
1055 static struct OptionInfo optionTable[] = {
1056
1057         { LibAliasOption,
1058                 PKT_ALIAS_UNREGISTERED_ONLY,
1059                 YesNo,
1060                 "[yes|no]",
1061                 "alias only unregistered addresses",
1062                 "unregistered_only",
1063                 "u" },
1064
1065         { LibAliasOption,
1066                 PKT_ALIAS_LOG,
1067                 YesNo,
1068                 "[yes|no]",
1069                 "enable logging",
1070                 "log",
1071                 "l" },
1072
1073         { LibAliasOption,
1074                 PKT_ALIAS_PROXY_ONLY,
1075                 YesNo,
1076                 "[yes|no]",
1077                 "proxy only",
1078                 "proxy_only",
1079                 NULL },
1080
1081         { LibAliasOption,
1082                 PKT_ALIAS_REVERSE,
1083                 YesNo,
1084                 "[yes|no]",
1085                 "operate in reverse mode",
1086                 "reverse",
1087                 NULL },
1088
1089         { LibAliasOption,
1090                 PKT_ALIAS_DENY_INCOMING,
1091                 YesNo,
1092                 "[yes|no]",
1093                 "allow incoming connections",
1094                 "deny_incoming",
1095                 "d" },
1096
1097         { LibAliasOption,
1098                 PKT_ALIAS_USE_SOCKETS,
1099                 YesNo,
1100                 "[yes|no]",
1101                 "use sockets to inhibit port conflict",
1102                 "use_sockets",
1103                 "s" },
1104
1105         { LibAliasOption,
1106                 PKT_ALIAS_SAME_PORTS,
1107                 YesNo,
1108                 "[yes|no]",
1109                 "try to keep original port numbers for connections",
1110                 "same_ports",
1111                 "m" },
1112
1113         { Verbose,
1114                 0,
1115                 YesNo,
1116                 "[yes|no]",
1117                 "verbose mode, dump packet information",
1118                 "verbose",
1119                 "v" },
1120         
1121         { DynamicMode,
1122                 0,
1123                 YesNo,
1124                 "[yes|no]",
1125                 "dynamic mode, automatically detect interface address changes",
1126                 "dynamic",
1127                 NULL },
1128         
1129         { InPort,
1130                 0,
1131                 Service,
1132                 "number|service_name",
1133                 "set port for incoming packets",
1134                 "in_port",
1135                 "i" },
1136         
1137         { OutPort,
1138                 0,
1139                 Service,
1140                 "number|service_name",
1141                 "set port for outgoing packets",
1142                 "out_port",
1143                 "o" },
1144         
1145         { Port,
1146                 0,
1147                 Service,
1148                 "number|service_name",
1149                 "set port (defaults to natd/divert)",
1150                 "port",
1151                 "p" },
1152         
1153         { GlobalPort,
1154                 0,
1155                 Service,
1156                 "number|service_name",
1157                 "set globalport",
1158                 "globalport",
1159                 NULL },
1160         
1161         { AliasAddress,
1162                 0,
1163                 Address,
1164                 "x.x.x.x",
1165                 "address to use for aliasing",
1166                 "alias_address",
1167                 "a" },
1168         
1169         { TargetAddress,
1170                 0,
1171                 Address,
1172                 "x.x.x.x",
1173                 "address to use for incoming sessions",
1174                 "target_address",
1175                 "t" },
1176         
1177         { InterfaceName,
1178                 0,
1179                 String,
1180                 "network_if_name",
1181                 "take aliasing address from interface",
1182                 "interface",
1183                 "n" },
1184
1185         { ProxyRule,
1186                 0,
1187                 String,
1188                 "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
1189                 "a.b.c.d:yyyy",
1190                 "add transparent proxying / destination NAT",
1191                 "proxy_rule",
1192                 NULL },
1193
1194         { RedirectPort,
1195                 0,
1196                 String,
1197                 "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
1198                 " [remote_addr[:remote_port_range]]",
1199                 "redirect a port (or ports) for incoming traffic",
1200                 "redirect_port",
1201                 NULL },
1202
1203         { RedirectProto,
1204                 0,
1205                 String,
1206                 "proto local_addr [public_addr] [remote_addr]",
1207                 "redirect packets of a given proto",
1208                 "redirect_proto",
1209                 NULL },
1210
1211         { RedirectAddress,
1212                 0,
1213                 String,
1214                 "local_addr[,...] public_addr",
1215                 "define mapping between local and public addresses",
1216                 "redirect_address",
1217                 NULL },
1218
1219         { ConfigFile,
1220                 0,
1221                 String,
1222                 "file_name",
1223                 "read options from configuration file",
1224                 "config",
1225                 "f" },
1226
1227         { LogDenied,
1228                 0,
1229                 YesNo,
1230                 "[yes|no]",
1231                 "enable logging of denied incoming packets",
1232                 "log_denied",
1233                 NULL },
1234
1235         { LogFacility,
1236                 0,
1237                 String,
1238                 "facility",
1239                 "name of syslog facility to use for logging",
1240                 "log_facility",
1241                 NULL },
1242
1243         { PunchFW,
1244                 0,
1245                 String,
1246                 "basenumber:count",
1247                 "punch holes in the firewall for incoming FTP/IRC DCC connections",
1248                 "punch_fw",
1249                 NULL },
1250
1251         { SkinnyPort,
1252                 0,
1253                 String,
1254                 "port",
1255                 "set the TCP port for use with the Skinny Station protocol",
1256                 "skinny_port",
1257                 NULL },
1258
1259         { LogIpfwDenied,
1260                 0,
1261                 YesNo,
1262                 "[yes|no]",
1263                 "log packets converted by natd, but denied by ipfw",
1264                 "log_ipfw_denied",
1265                 NULL },
1266
1267         { PidFile,
1268                 0,
1269                 String,
1270                 "file_name",
1271                 "store PID in an alternate file",
1272                 "pid_file",
1273                 "P" },
1274         { Instance,
1275                 0,
1276                 String,
1277                 "instance name",
1278                 "name of aliasing engine instance",
1279                 "instance",
1280                 NULL },
1281 };
1282         
1283 static void ParseOption (const char* option, const char* parms)
1284 {
1285         int                     i;
1286         struct OptionInfo*      info;
1287         int                     yesNoValue;
1288         int                     aliasValue;
1289         int                     numValue;
1290         u_short                 uNumValue;
1291         const char*             strValue;
1292         struct in_addr          addrValue;
1293         int                     max;
1294         char*                   end;
1295         CODE*                   fac_record = NULL;
1296 /*
1297  * Find option from table.
1298  */
1299         max = sizeof (optionTable) / sizeof (struct OptionInfo);
1300         for (i = 0, info = optionTable; i < max; i++, info++) {
1301
1302                 if (!strcmp (info->name, option))
1303                         break;
1304
1305                 if (info->shortName)
1306                         if (!strcmp (info->shortName, option))
1307                                 break;
1308         }
1309
1310         if (i >= max) {
1311
1312                 warnx ("unknown option %s", option);
1313                 Usage ();
1314         }
1315
1316         uNumValue       = 0;
1317         yesNoValue      = 0;
1318         numValue        = 0;
1319         strValue        = NULL;
1320 /*
1321  * Check parameters.
1322  */
1323         switch (info->parm) {
1324         case YesNo:
1325                 if (!parms)
1326                         parms = "yes";
1327
1328                 if (!strcmp (parms, "yes"))
1329                         yesNoValue = 1;
1330                 else
1331                         if (!strcmp (parms, "no"))
1332                                 yesNoValue = 0;
1333                         else
1334                                 errx (1, "%s needs yes/no parameter", option);
1335                 break;
1336
1337         case Service:
1338                 if (!parms)
1339                         errx (1, "%s needs service name or "
1340                                  "port number parameter",
1341                                  option);
1342
1343                 uNumValue = StrToPort (parms, "divert");
1344                 break;
1345
1346         case Numeric:
1347                 if (parms)
1348                         numValue = strtol (parms, &end, 10);
1349                 else
1350                         end = NULL;
1351
1352                 if (end == parms)
1353                         errx (1, "%s needs numeric parameter", option);
1354                 break;
1355
1356         case String:
1357                 strValue = parms;
1358                 if (!strValue)
1359                         errx (1, "%s needs parameter", option);
1360                 break;
1361
1362         case None:
1363                 if (parms)
1364                         errx (1, "%s does not take parameters", option);
1365                 break;
1366
1367         case Address:
1368                 if (!parms)
1369                         errx (1, "%s needs address/host parameter", option);
1370
1371                 StrToAddr (parms, &addrValue);
1372                 break;
1373         }
1374
1375         switch (info->type) {
1376         case LibAliasOption:
1377         
1378                 aliasValue = yesNoValue ? info->packetAliasOpt : 0;
1379                 LibAliasSetMode (mla, aliasValue, info->packetAliasOpt);
1380                 break;
1381
1382         case Verbose:
1383                 verbose = yesNoValue;
1384                 break;
1385
1386         case DynamicMode:
1387                 dynamicMode = yesNoValue;
1388                 break;
1389
1390         case InPort:
1391                 mip->inPort = uNumValue;
1392                 break;
1393
1394         case OutPort:
1395                 mip->outPort = uNumValue;
1396                 break;
1397
1398         case Port:
1399                 mip->inOutPort = uNumValue;
1400                 break;
1401
1402         case GlobalPort:
1403                 globalPort = uNumValue;
1404                 break;
1405
1406         case AliasAddress:
1407                 memcpy (&mip->aliasAddr, &addrValue, sizeof (struct in_addr));
1408                 break;
1409
1410         case TargetAddress:
1411                 LibAliasSetTarget(mla, addrValue);
1412                 break;
1413
1414         case RedirectPort:
1415                 SetupPortRedirect (strValue);
1416                 break;
1417
1418         case RedirectProto:
1419                 SetupProtoRedirect(strValue);
1420                 break;
1421
1422         case RedirectAddress:
1423                 SetupAddressRedirect (strValue);
1424                 break;
1425
1426         case ProxyRule:
1427                 LibAliasProxyRule (mla, strValue);
1428                 break;
1429
1430         case InterfaceName:
1431                 if (mip->ifName)
1432                         free (mip->ifName);
1433
1434                 mip->ifName = strdup (strValue);
1435                 break;
1436
1437         case ConfigFile:
1438                 ReadConfigFile (strValue);
1439                 break;
1440
1441         case LogDenied:
1442                 mip->logDropped = yesNoValue;
1443                 break;
1444
1445         case LogFacility:
1446
1447                 fac_record = facilitynames;
1448                 while (fac_record->c_name != NULL) {
1449
1450                         if (!strcmp (fac_record->c_name, strValue)) {
1451
1452                                 logFacility = fac_record->c_val;
1453                                 break;
1454
1455                         }
1456                         else
1457                                 fac_record++;
1458                 }
1459
1460                 if(fac_record->c_name == NULL)
1461                         errx(1, "Unknown log facility name: %s", strValue);     
1462
1463                 break;
1464
1465         case PunchFW:
1466                 SetupPunchFW(strValue);
1467                 break;
1468
1469         case SkinnyPort:
1470                 SetupSkinnyPort(strValue);
1471                 break;
1472
1473         case LogIpfwDenied:
1474                 logIpfwDenied = yesNoValue;;
1475                 break;
1476
1477         case PidFile:
1478                 pidName = strdup (strValue);
1479                 break;
1480         case Instance:
1481                 NewInstance(strValue);
1482                 break;
1483         }
1484 }
1485
1486 void ReadConfigFile (const char* fileName)
1487 {
1488         FILE*   file;
1489         char    *buf;
1490         size_t  len;
1491         char    *ptr, *p;
1492         char*   option;
1493
1494         file = fopen (fileName, "r");
1495         if (!file)
1496                 err(1, "cannot open config file %s", fileName);
1497
1498         while ((buf = fgetln(file, &len)) != NULL) {
1499                 if (buf[len - 1] == '\n')
1500                         buf[len - 1] = '\0';
1501                 else
1502                         errx(1, "config file format error: "
1503                                 "last line should end with newline");
1504
1505 /*
1506  * Check for comments, strip off trailing spaces.
1507  */
1508                 if ((ptr = strchr(buf, '#')))
1509                         *ptr = '\0';
1510                 for (ptr = buf; isspace(*ptr); ++ptr)
1511                         continue;
1512                 if (*ptr == '\0')
1513                         continue;
1514                 for (p = strchr(buf, '\0'); isspace(*--p);)
1515                         continue;
1516                 *++p = '\0';
1517
1518 /*
1519  * Extract option name.
1520  */
1521                 option = ptr;
1522                 while (*ptr && !isspace (*ptr))
1523                         ++ptr;
1524
1525                 if (*ptr != '\0') {
1526
1527                         *ptr = '\0';
1528                         ++ptr;
1529                 }
1530 /*
1531  * Skip white space between name and parms.
1532  */
1533                 while (*ptr && isspace (*ptr))
1534                         ++ptr;
1535
1536                 ParseOption (option, *ptr ? ptr : NULL);
1537         }
1538
1539         fclose (file);
1540 }
1541
1542 static void Usage ()
1543 {
1544         int                     i;
1545         int                     max;
1546         struct OptionInfo*      info;
1547
1548         fprintf (stderr, "Recognized options:\n\n");
1549
1550         max = sizeof (optionTable) / sizeof (struct OptionInfo);
1551         for (i = 0, info = optionTable; i < max; i++, info++) {
1552
1553                 fprintf (stderr, "-%-20s %s\n", info->name,
1554                                                 info->parmDescription);
1555
1556                 if (info->shortName)
1557                         fprintf (stderr, "-%-20s %s\n", info->shortName,
1558                                                         info->parmDescription);
1559
1560                 fprintf (stderr, "      %s\n\n", info->description);
1561         }
1562
1563         exit (1);
1564 }
1565
1566 void SetupPortRedirect (const char* parms)
1567 {
1568         char            buf[128];
1569         char*           ptr;
1570         char*           serverPool;
1571         struct in_addr  localAddr;
1572         struct in_addr  publicAddr;
1573         struct in_addr  remoteAddr;
1574         port_range      portRange;
1575         u_short         localPort      = 0;
1576         u_short         publicPort     = 0;
1577         u_short         remotePort     = 0;
1578         u_short         numLocalPorts  = 0;
1579         u_short         numPublicPorts = 0;
1580         u_short         numRemotePorts = 0;
1581         int             proto;
1582         char*           protoName;
1583         char*           separator;
1584         int             i;
1585         struct alias_link *aliaslink = NULL;
1586
1587         strlcpy (buf, parms, sizeof(buf));
1588 /*
1589  * Extract protocol.
1590  */
1591         protoName = strtok (buf, " \t");
1592         if (!protoName)
1593                 errx (1, "redirect_port: missing protocol");
1594
1595         proto = StrToProto (protoName);
1596 /*
1597  * Extract local address.
1598  */
1599         ptr = strtok (NULL, " \t");
1600         if (!ptr)
1601                 errx (1, "redirect_port: missing local address");
1602
1603         separator = strchr(ptr, ',');
1604         if (separator) {                /* LSNAT redirection syntax. */
1605                 localAddr.s_addr = INADDR_NONE;
1606                 localPort = ~0;
1607                 numLocalPorts = 1;
1608                 serverPool = ptr;
1609         } else {
1610                 if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 )
1611                         errx (1, "redirect_port: invalid local port range");
1612
1613                 localPort     = GETLOPORT(portRange);
1614                 numLocalPorts = GETNUMPORTS(portRange);
1615                 serverPool = NULL;
1616         }
1617
1618 /*
1619  * Extract public port and optionally address.
1620  */
1621         ptr = strtok (NULL, " \t");
1622         if (!ptr)
1623                 errx (1, "redirect_port: missing public port");
1624
1625         separator = strchr (ptr, ':');
1626         if (separator) {
1627                 if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 )
1628                         errx (1, "redirect_port: invalid public port range");
1629         }
1630         else {
1631                 publicAddr.s_addr = INADDR_ANY;
1632                 if (StrToPortRange (ptr, protoName, &portRange) != 0)
1633                         errx (1, "redirect_port: invalid public port range");
1634         }
1635
1636         publicPort     = GETLOPORT(portRange);
1637         numPublicPorts = GETNUMPORTS(portRange);
1638
1639 /*
1640  * Extract remote address and optionally port.
1641  */
1642         ptr = strtok (NULL, " \t");
1643         if (ptr) {
1644                 separator = strchr (ptr, ':');
1645                 if (separator) {
1646                         if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0)
1647                                 errx (1, "redirect_port: invalid remote port range");
1648                 } else {
1649                         SETLOPORT(portRange, 0);
1650                         SETNUMPORTS(portRange, 1);
1651                         StrToAddr (ptr, &remoteAddr);
1652                 }
1653         }
1654         else {
1655                 SETLOPORT(portRange, 0);
1656                 SETNUMPORTS(portRange, 1);
1657                 remoteAddr.s_addr = INADDR_ANY;
1658         }
1659
1660         remotePort     = GETLOPORT(portRange);
1661         numRemotePorts = GETNUMPORTS(portRange);
1662
1663 /*
1664  * Make sure port ranges match up, then add the redirect ports.
1665  */
1666         if (numLocalPorts != numPublicPorts)
1667                 errx (1, "redirect_port: port ranges must be equal in size");
1668
1669         /* Remote port range is allowed to be '0' which means all ports. */
1670         if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0))
1671                 errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
1672
1673         for (i = 0 ; i < numPublicPorts ; ++i) {
1674                 /* If remotePort is all ports, set it to 0. */
1675                 u_short remotePortCopy = remotePort + i;
1676                 if (numRemotePorts == 1 && remotePort == 0)
1677                         remotePortCopy = 0;
1678
1679                 aliaslink = LibAliasRedirectPort (mla, localAddr,
1680                                                 htons(localPort + i),
1681                                                 remoteAddr,
1682                                                 htons(remotePortCopy),
1683                                                 publicAddr,
1684                                                 htons(publicPort + i),
1685                                                 proto);
1686         }
1687
1688 /*
1689  * Setup LSNAT server pool.
1690  */
1691         if (serverPool != NULL && aliaslink != NULL) {
1692                 ptr = strtok(serverPool, ",");
1693                 while (ptr != NULL) {
1694                         if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0)
1695                                 errx(1, "redirect_port: invalid local port range");
1696
1697                         localPort = GETLOPORT(portRange);
1698                         if (GETNUMPORTS(portRange) != 1)
1699                                 errx(1, "redirect_port: local port must be single in this context");
1700                         LibAliasAddServer(mla, aliaslink, localAddr, htons(localPort));
1701                         ptr = strtok(NULL, ",");
1702                 }
1703         }
1704 }
1705
1706 void
1707 SetupProtoRedirect(const char* parms)
1708 {
1709         char            buf[128];
1710         char*           ptr;
1711         struct in_addr  localAddr;
1712         struct in_addr  publicAddr;
1713         struct in_addr  remoteAddr;
1714         int             proto;
1715         char*           protoName;
1716         struct protoent *protoent;
1717
1718         strlcpy (buf, parms, sizeof(buf));
1719 /*
1720  * Extract protocol.
1721  */
1722         protoName = strtok(buf, " \t");
1723         if (!protoName)
1724                 errx(1, "redirect_proto: missing protocol");
1725
1726         protoent = getprotobyname(protoName);
1727         if (protoent == NULL)
1728                 errx(1, "redirect_proto: unknown protocol %s", protoName);
1729         else
1730                 proto = protoent->p_proto;
1731 /*
1732  * Extract local address.
1733  */
1734         ptr = strtok(NULL, " \t");
1735         if (!ptr)
1736                 errx(1, "redirect_proto: missing local address");
1737         else
1738                 StrToAddr(ptr, &localAddr);
1739 /*
1740  * Extract optional public address.
1741  */
1742         ptr = strtok(NULL, " \t");
1743         if (ptr)
1744                 StrToAddr(ptr, &publicAddr);
1745         else
1746                 publicAddr.s_addr = INADDR_ANY;
1747 /*
1748  * Extract optional remote address.
1749  */
1750         ptr = strtok(NULL, " \t");
1751         if (ptr)
1752                 StrToAddr(ptr, &remoteAddr);
1753         else
1754                 remoteAddr.s_addr = INADDR_ANY;
1755 /*
1756  * Create aliasing link.
1757  */
1758         (void)LibAliasRedirectProto(mla, localAddr, remoteAddr, publicAddr,
1759                                        proto);
1760 }
1761
1762 void SetupAddressRedirect (const char* parms)
1763 {
1764         char            buf[128];
1765         char*           ptr;
1766         char*           separator;
1767         struct in_addr  localAddr;
1768         struct in_addr  publicAddr;
1769         char*           serverPool;
1770         struct alias_link *aliaslink;
1771
1772         strlcpy (buf, parms, sizeof(buf));
1773 /*
1774  * Extract local address.
1775  */
1776         ptr = strtok (buf, " \t");
1777         if (!ptr)
1778                 errx (1, "redirect_address: missing local address");
1779
1780         separator = strchr(ptr, ',');
1781         if (separator) {                /* LSNAT redirection syntax. */
1782                 localAddr.s_addr = INADDR_NONE;
1783                 serverPool = ptr;
1784         } else {
1785                 StrToAddr (ptr, &localAddr);
1786                 serverPool = NULL;
1787         }
1788 /*
1789  * Extract public address.
1790  */
1791         ptr = strtok (NULL, " \t");
1792         if (!ptr)
1793                 errx (1, "redirect_address: missing public address");
1794
1795         StrToAddr (ptr, &publicAddr);
1796         aliaslink = LibAliasRedirectAddr(mla, localAddr, publicAddr);
1797
1798 /*
1799  * Setup LSNAT server pool.
1800  */
1801         if (serverPool != NULL && aliaslink != NULL) {
1802                 ptr = strtok(serverPool, ",");
1803                 while (ptr != NULL) {
1804                         StrToAddr(ptr, &localAddr);
1805                         LibAliasAddServer(mla, aliaslink, localAddr, htons(~0));
1806                         ptr = strtok(NULL, ",");
1807                 }
1808         }
1809 }
1810
1811 void StrToAddr (const char* str, struct in_addr* addr)
1812 {
1813         struct hostent* hp;
1814
1815         if (inet_aton (str, addr))
1816                 return;
1817
1818         hp = gethostbyname (str);
1819         if (!hp)
1820                 errx (1, "unknown host %s", str);
1821
1822         memcpy (addr, hp->h_addr, sizeof (struct in_addr));
1823 }
1824
1825 u_short StrToPort (const char* str, const char* proto)
1826 {
1827         u_short         port;
1828         struct servent* sp;
1829         char*           end;
1830
1831         port = strtol (str, &end, 10);
1832         if (end != str)
1833                 return htons (port);
1834
1835         sp = getservbyname (str, proto);
1836         if (!sp)
1837                 errx (1, "%s/%s: unknown service", str, proto);
1838
1839         return sp->s_port;
1840 }
1841
1842 int StrToPortRange (const char* str, const char* proto, port_range *portRange)
1843 {
1844         char*           sep;
1845         struct servent* sp;
1846         char*           end;
1847         u_short         loPort;
1848         u_short         hiPort;
1849         
1850         /* First see if this is a service, return corresponding port if so. */
1851         sp = getservbyname (str,proto);
1852         if (sp) {
1853                 SETLOPORT(*portRange, ntohs(sp->s_port));
1854                 SETNUMPORTS(*portRange, 1);
1855                 return 0;
1856         }
1857                 
1858         /* Not a service, see if it's a single port or port range. */
1859         sep = strchr (str, '-');
1860         if (sep == NULL) {
1861                 SETLOPORT(*portRange, strtol(str, &end, 10));
1862                 if (end != str) {
1863                         /* Single port. */
1864                         SETNUMPORTS(*portRange, 1);
1865                         return 0;
1866                 }
1867
1868                 /* Error in port range field. */
1869                 errx (1, "%s/%s: unknown service", str, proto);
1870         }
1871
1872         /* Port range, get the values and sanity check. */
1873         sscanf (str, "%hu-%hu", &loPort, &hiPort);
1874         SETLOPORT(*portRange, loPort);
1875         SETNUMPORTS(*portRange, 0);     /* Error by default */
1876         if (loPort <= hiPort)
1877                 SETNUMPORTS(*portRange, hiPort - loPort + 1);
1878
1879         if (GETNUMPORTS(*portRange) == 0)
1880                 errx (1, "invalid port range %s", str);
1881
1882         return 0;
1883 }
1884
1885
1886 int StrToProto (const char* str)
1887 {
1888         if (!strcmp (str, "tcp"))
1889                 return IPPROTO_TCP;
1890
1891         if (!strcmp (str, "udp"))
1892                 return IPPROTO_UDP;
1893
1894         errx (1, "unknown protocol %s. Expected tcp or udp", str);
1895 }
1896
1897 int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange)
1898 {
1899         char*   ptr;
1900
1901         ptr = strchr (str, ':');
1902         if (!ptr)
1903                 errx (1, "%s is missing port number", str);
1904
1905         *ptr = '\0';
1906         ++ptr;
1907
1908         StrToAddr (str, addr);
1909         return StrToPortRange (ptr, proto, portRange);
1910 }
1911
1912 static void
1913 SetupPunchFW(const char *strValue)
1914 {
1915         unsigned int base, num;
1916
1917         if (sscanf(strValue, "%u:%u", &base, &num) != 2)
1918                 errx(1, "punch_fw: basenumber:count parameter required");
1919
1920         if (CheckIpfwRulenum(base + num - 1) == -1)
1921                 errx(1, "punch_fw: basenumber:count parameter should fit "
1922                         "the maximum allowed rule numbers");
1923
1924         LibAliasSetFWBase(mla, base, num);
1925         (void)LibAliasSetMode(mla, PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);
1926 }
1927
1928 static void
1929 SetupSkinnyPort(const char *strValue)
1930 {
1931         unsigned int port;
1932
1933         if (sscanf(strValue, "%u", &port) != 1)
1934                 errx(1, "skinny_port: port parameter required");
1935
1936         LibAliasSetSkinnyPort(mla, port);
1937 }
1938
1939 static void
1940 NewInstance(const char *name)
1941 {
1942         struct instance *ip;
1943
1944         LIST_FOREACH(ip, &root, list) {
1945                 if (!strcmp(ip->name, name)) {
1946                         mla = ip->la;
1947                         mip = ip;
1948                         return;
1949                 }
1950         }
1951         ninstance++;
1952         ip = calloc(sizeof *ip, 1);
1953         ip->name = strdup(name);
1954         ip->la = LibAliasInit (ip->la);
1955         ip->assignAliasAddr     = 0;
1956         ip->ifName              = NULL;
1957         ip->logDropped          = 0;
1958         ip->inPort              = 0;
1959         ip->outPort             = 0;
1960         ip->inOutPort           = 0;
1961         ip->aliasAddr.s_addr    = INADDR_NONE;
1962         ip->ifMTU               = -1;
1963         ip->aliasOverhead       = 12;
1964         LIST_INSERT_HEAD(&root, ip, list);
1965         mla = ip->la;
1966         mip = ip;
1967 }
1968
1969 static int
1970 CheckIpfwRulenum(unsigned int rnum)
1971 {
1972         unsigned int default_rule;
1973         size_t len = sizeof(default_rule);
1974
1975         if (sysctlbyname("net.inet.ip.fw.default_rule", &default_rule, &len,
1976                 NULL, 0) == -1) {
1977                 warn("Failed to get the default ipfw rule number, using "
1978                      "default historical value 65535.  The reason was");
1979                 default_rule = 65535;
1980         }
1981         if (rnum >= default_rule) {
1982                 return -1;
1983         }
1984
1985         return 0;
1986 }