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