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