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