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