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