MFC: Fix a panic on boot that can occur if you hit keys on the keyboard
[dragonfly.git] / sbin / natd / natd.c
blob2188703a043af8a317c6993b4f37060c2be947cc
1 /*
2 * natd - Network Address Translation Daemon for FreeBSD.
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.
8 * You may copy, modify and distribute this software (natd.c) freely.
10 * Ari Suutari <suutari@iki.fi>
12 * $FreeBSD: src/sbin/natd/natd.c,v 1.25.2.5 2002/02/01 09:18:32 ru Exp $
13 * $DragonFly: src/sbin/natd/natd.c,v 1.11 2006/08/03 16:40:46 swildner Exp $
16 #define SYSLOG_NAMES
18 #include <sys/param.h>
19 #include <sys/socket.h>
20 #include <sys/sysctl.h>
21 #include <sys/time.h>
23 #include <netinet/in.h>
24 #include <netinet/in_systm.h>
25 #include <netinet/ip.h>
26 #include <netinet/tcp.h>
27 #include <netinet/udp.h>
28 #include <netinet/ip_icmp.h>
29 #include <net/if.h>
30 #include <net/if_dl.h>
31 #include <net/route.h>
32 #include <arpa/inet.h>
34 #include <alias.h>
35 #include <ctype.h>
36 #include <err.h>
37 #include <errno.h>
38 #include <netdb.h>
39 #include <signal.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <syslog.h>
44 #include <unistd.h>
46 #include "natd.h"
49 * Default values for input and output
50 * divert socket ports.
53 #define DEFAULT_SERVICE "natd"
56 * Definition of a port range, and macros to deal with values.
57 * FORMAT: HI 16-bits == first port in range, 0 == all ports.
58 * LO 16-bits == number of ports in range
59 * NOTES: - Port values are not stored in network byte order.
62 typedef u_long port_range;
64 #define GETLOPORT(x) ((x) >> 0x10)
65 #define GETNUMPORTS(x) ((x) & 0x0000ffff)
66 #define GETHIPORT(x) (GETLOPORT((x)) + GETNUMPORTS((x)))
68 /* Set y to be the low-port value in port_range variable x. */
69 #define SETLOPORT(x,y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
71 /* Set y to be the number of ports in port_range variable x. */
72 #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y))
75 * Function prototypes.
78 static void DoAliasing(int, int);
79 static void DaemonMode(void);
80 static void HandleRoutingInfo(int);
81 static void Usage(void);
82 static char* FormatPacket(struct ip *);
83 static void PrintPacket(struct ip *);
84 static void SyslogPacket(struct ip *, int, const char *);
85 static void SetAliasAddressFromIfName(const char *);
86 static void InitiateShutdown(int);
87 static void Shutdown(int);
88 static void RefreshAddr(int);
89 static void ParseOption(const char *, const char *);
90 static void ReadConfigFile(const char *);
91 static void SetupPortRedirect(const char *);
92 static void SetupProtoRedirect(const char *);
93 static void SetupAddressRedirect(const char *);
94 static void StrToAddr(const char *, struct in_addr *);
95 static u_short StrToPort(const char *, const char *);
96 static int StrToPortRange(const char *, const char *, port_range *);
97 static int StrToProto(const char *);
98 static int StrToAddrAndPortRange(const char *, struct in_addr *, char *, port_range *);
99 static void ParseArgs(int, char **);
100 static void SetupPunchFW(const char *);
103 * Globals.
106 static int verbose;
107 static int background;
108 static volatile sig_atomic_t running;
109 static volatile sig_atomic_t assignAliasAddr;
110 static char* ifName;
111 static int ifIndex;
112 static u_short inPort;
113 static u_short outPort;
114 static u_short inOutPort;
115 static struct in_addr aliasAddr;
116 static int dynamicMode;
117 static int ifMTU;
118 static int aliasOverhead;
119 static int icmpSock;
120 static int dropIgnoredIncoming;
121 static int logDropped;
122 static int logFacility;
123 static int logIpfwDenied;
126 main(int argc, char **argv)
128 int divertIn;
129 int divertOut;
130 int divertInOut;
131 int routeSock;
132 struct sockaddr_in addr;
133 fd_set readMask;
134 int fdMax;
135 struct sigaction sa;
137 * Initialize packet aliasing software.
138 * Done already here to be able to alter option bits
139 * during command line and configuration file processing.
141 PacketAliasInit();
143 * Parse options.
145 inPort = 0;
146 outPort = 0;
147 verbose = 0;
148 inOutPort = 0;
149 ifName = NULL;
150 ifMTU = -1;
151 background = 0;
152 running = 1;
153 assignAliasAddr = 0;
154 aliasAddr.s_addr = INADDR_NONE;
155 aliasOverhead = 12;
156 dynamicMode = 0;
157 logDropped = 0;
158 logFacility = LOG_DAEMON;
159 logIpfwDenied = -1;
161 ParseArgs(argc, argv);
163 * Log ipfw(8) denied packets by default in verbose mode.
165 if (logIpfwDenied == -1)
166 logIpfwDenied = verbose;
168 * Open syslog channel.
170 openlog("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0),
171 logFacility);
173 * Check that valid aliasing address has been given.
175 if (aliasAddr.s_addr == INADDR_NONE && ifName == NULL)
176 errx(1, "aliasing address not given");
178 if (aliasAddr.s_addr != INADDR_NONE && ifName != NULL)
179 errx(1, "both alias address and interface "
180 "name are not allowed");
182 * Check that valid port number is known.
184 if (inPort != 0 || outPort != 0)
185 if (inPort == 0 || outPort == 0)
186 errx(1, "both input and output ports are required");
188 if (inPort == 0 && outPort == 0 && inOutPort == 0)
189 ParseOption("port", DEFAULT_SERVICE);
192 * Check if ignored packets should be dropped.
194 dropIgnoredIncoming = PacketAliasSetMode(0, 0);
195 dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING;
197 * Create divert sockets. Use only one socket if -p was specified
198 * on command line. Otherwise, create separate sockets for
199 * outgoing and incoming connnections.
201 if (inOutPort) {
202 divertInOut = socket(PF_INET, SOCK_RAW, IPPROTO_DIVERT);
203 if (divertInOut == -1)
204 Quit("Unable to create divert socket.");
206 divertIn = -1;
207 divertOut = -1;
209 * Bind socket.
212 addr.sin_family = AF_INET;
213 addr.sin_addr.s_addr = INADDR_ANY;
214 addr.sin_port = inOutPort;
216 if (bind(divertInOut,
217 (struct sockaddr *)&addr,
218 sizeof addr) == -1)
219 Quit("Unable to bind divert socket.");
220 } else {
221 divertIn = socket(PF_INET, SOCK_RAW, IPPROTO_DIVERT);
222 if (divertIn == -1)
223 Quit("Unable to create incoming divert socket.");
225 divertOut = socket(PF_INET, SOCK_RAW, IPPROTO_DIVERT);
226 if (divertOut == -1)
227 Quit("Unable to create outgoing divert socket.");
229 divertInOut = -1;
232 * Bind divert sockets.
235 addr.sin_family = AF_INET;
236 addr.sin_addr.s_addr = INADDR_ANY;
237 addr.sin_port = inPort;
239 if (bind(divertIn,
240 (struct sockaddr *)&addr,
241 sizeof addr) == -1)
242 Quit("Unable to bind incoming divert socket.");
244 addr.sin_family = AF_INET;
245 addr.sin_addr.s_addr = INADDR_ANY;
246 addr.sin_port = outPort;
248 if (bind(divertOut,
249 (struct sockaddr *)&addr,
250 sizeof addr) == -1)
251 Quit("Unable to bind outgoing divert socket.");
254 * Create routing socket if interface name specified and in dynamic mode.
256 routeSock = -1;
257 if (ifName) {
258 if (dynamicMode) {
259 routeSock = socket(PF_ROUTE, SOCK_RAW, 0);
260 if (routeSock == -1)
261 Quit("Unable to create routing info socket.");
263 assignAliasAddr = 1;
264 } else
265 SetAliasAddressFromIfName(ifName);
268 * Create socket for sending ICMP messages.
270 icmpSock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
271 if (icmpSock == -1)
272 Quit("Unable to create ICMP socket.");
275 * And disable reads for the socket, otherwise it slowly fills
276 * up with received icmps which we do not use.
278 shutdown(icmpSock, SHUT_RD);
281 * Become a daemon unless verbose mode was requested.
283 if (!verbose)
284 DaemonMode();
286 * Catch signals to manage shutdown and
287 * refresh of interface address.
289 sa.sa_handler = InitiateShutdown;
290 sa.sa_flags = 0;
291 sigemptyset(&sa.sa_mask);
292 sigaction(SIGTERM, &sa, NULL);
293 sa.sa_handler = RefreshAddr;
294 sigaction(SIGHUP, &sa, NULL);
296 * Set alias address if it has been given.
298 if (aliasAddr.s_addr != INADDR_NONE)
299 PacketAliasSetAddress(aliasAddr);
301 * We need largest descriptor number for select.
304 fdMax = -1;
306 if (divertIn > fdMax)
307 fdMax = divertIn;
309 if (divertOut > fdMax)
310 fdMax = divertOut;
312 if (divertInOut > fdMax)
313 fdMax = divertInOut;
315 if (routeSock > fdMax)
316 fdMax = routeSock;
318 while (running) {
319 if (divertInOut != -1 && !ifName) {
321 * When using only one socket, just call
322 * DoAliasing repeatedly to process packets.
324 DoAliasing(divertInOut, DONT_KNOW);
325 continue;
328 * Build read mask from socket descriptors to select.
330 FD_ZERO(&readMask);
332 * Check if new packets are available.
334 if (divertIn != -1)
335 FD_SET(divertIn, &readMask);
337 if (divertOut != -1)
338 FD_SET(divertOut, &readMask);
340 if (divertInOut != -1)
341 FD_SET(divertInOut, &readMask);
343 * Routing info is processed always.
345 if (routeSock != -1)
346 FD_SET(routeSock, &readMask);
348 if (select(fdMax + 1,
349 &readMask,
350 NULL,
351 NULL,
352 NULL) == -1) {
353 if (errno == EINTR)
354 continue;
356 Quit("Select failed.");
359 if (divertIn != -1)
360 if (FD_ISSET(divertIn, &readMask))
361 DoAliasing(divertIn, INPUT);
363 if (divertOut != -1)
364 if (FD_ISSET(divertOut, &readMask))
365 DoAliasing(divertOut, OUTPUT);
367 if (divertInOut != -1)
368 if (FD_ISSET(divertInOut, &readMask))
369 DoAliasing(divertInOut, DONT_KNOW);
371 if (routeSock != -1)
372 if (FD_ISSET(routeSock, &readMask))
373 HandleRoutingInfo(routeSock);
376 if (background)
377 unlink(PIDFILE);
379 return 0;
382 static void
383 DaemonMode(void)
385 FILE* pidFile;
387 daemon(0, 0);
388 background = 1;
390 pidFile = fopen(PIDFILE, "w");
391 if (pidFile) {
392 fprintf(pidFile, "%d\n", getpid());
393 fclose(pidFile);
397 static void
398 ParseArgs(int argc, char **argv)
400 int arg;
401 char* opt;
402 char parmBuf[256];
403 int len; /* bounds checking */
405 for (arg = 1; arg < argc; arg++) {
406 opt = argv[arg];
407 if (*opt != '-') {
408 warnx("invalid option %s", opt);
409 Usage();
412 parmBuf[0] = '\0';
413 len = 0;
415 while (arg < argc - 1) {
416 if (argv[arg + 1][0] == '-')
417 break;
419 if (len) {
420 strncat(parmBuf, " ", sizeof(parmBuf) - (len + 1));
421 len += strlen(parmBuf + len);
424 ++arg;
425 strncat(parmBuf, argv[arg], sizeof(parmBuf) - (len + 1));
426 len += strlen(parmBuf + len);
430 ParseOption(opt + 1, (len ? parmBuf : NULL));
435 static void
436 DoAliasing(int fd, int direction)
438 int bytes;
439 int origBytes;
440 char buf[IP_MAXPACKET];
441 struct sockaddr_in addr;
442 int wrote;
443 int status;
444 int addrSize;
445 struct ip* ip;
446 char msgBuf[80];
448 if (assignAliasAddr) {
449 SetAliasAddressFromIfName(ifName);
450 assignAliasAddr = 0;
453 * Get packet from socket.
455 addrSize = sizeof addr;
456 origBytes = recvfrom(fd,
457 buf,
458 sizeof buf,
460 (struct sockaddr *)&addr,
461 &addrSize);
463 if (origBytes == -1) {
464 if (errno != EINTR)
465 Warn("read from divert socket failed");
467 return;
470 * This is a IP packet.
472 ip = (struct ip *)buf;
473 if (direction == DONT_KNOW) {
474 if (addr.sin_addr.s_addr == INADDR_ANY)
475 direction = OUTPUT;
476 else
477 direction = INPUT;
480 if (verbose) {
482 * Print packet direction and protocol type.
484 printf(direction == OUTPUT ? "Out " : "In ");
486 switch (ip->ip_p) {
487 case IPPROTO_TCP:
488 printf("[TCP] ");
489 break;
491 case IPPROTO_UDP:
492 printf("[UDP] ");
493 break;
495 case IPPROTO_ICMP:
496 printf("[ICMP] ");
497 break;
499 default:
500 printf("[%d] ", ip->ip_p);
501 break;
504 * Print addresses.
506 PrintPacket(ip);
509 if (direction == OUTPUT) {
511 * Outgoing packets. Do aliasing.
513 PacketAliasOut(buf, IP_MAXPACKET);
514 } else {
516 * Do aliasing.
518 status = PacketAliasIn(buf, IP_MAXPACKET);
519 if (status == PKT_ALIAS_IGNORED &&
520 dropIgnoredIncoming) {
521 if (verbose)
522 printf(" dropped.\n");
524 if (logDropped)
525 SyslogPacket(ip, LOG_WARNING, "denied");
527 return;
531 * Length might have changed during aliasing.
533 bytes = ntohs(ip->ip_len);
535 * Update alias overhead size for outgoing packets.
537 if (direction == OUTPUT &&
538 bytes - origBytes > aliasOverhead)
539 aliasOverhead = bytes - origBytes;
541 if (verbose) {
543 * Print addresses after aliasing.
545 printf(" aliased to\n");
546 printf(" ");
547 PrintPacket(ip);
548 printf("\n");
552 * Put packet back for processing.
554 wrote = sendto(fd,
555 buf,
556 bytes,
558 (struct sockaddr *)&addr,
559 sizeof addr);
561 if (wrote != bytes) {
562 if (errno == EMSGSIZE) {
563 if (direction == OUTPUT &&
564 ifMTU != -1)
565 SendNeedFragIcmp(icmpSock,
566 (struct ip *)buf,
567 ifMTU - aliasOverhead);
568 } else if (errno == EACCES && logIpfwDenied) {
569 sprintf(msgBuf, "failed to write packet back");
570 Warn(msgBuf);
575 static void
576 HandleRoutingInfo(int fd)
578 int bytes;
579 struct if_msghdr ifMsg;
581 * Get packet from socket.
583 bytes = read(fd, &ifMsg, sizeof ifMsg);
584 if (bytes == -1) {
585 Warn("read from routing socket failed");
586 return;
589 if (ifMsg.ifm_version != RTM_VERSION) {
590 Warn("unexpected packet read from routing socket");
591 return;
594 if (verbose)
595 printf("Routing message %#x received.\n", ifMsg.ifm_type);
597 if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO) &&
598 ifMsg.ifm_index == ifIndex) {
599 if (verbose)
600 printf("Interface address/MTU has probably changed.\n");
601 assignAliasAddr = 1;
605 static void
606 PrintPacket(struct ip *ip)
608 printf("%s", FormatPacket(ip));
611 static void
612 SyslogPacket(struct ip *ip, int priority, const char *label)
614 syslog(priority, "%s %s", label, FormatPacket(ip));
617 static char*
618 FormatPacket(struct ip *ip)
620 static char buf[256];
621 struct tcphdr* tcphdr;
622 struct udphdr* udphdr;
623 struct icmp* icmphdr;
624 char src[20];
625 char dst[20];
627 strcpy(src, inet_ntoa(ip->ip_src));
628 strcpy(dst, inet_ntoa(ip->ip_dst));
630 switch (ip->ip_p) {
631 case IPPROTO_TCP:
632 tcphdr = (struct tcphdr *)((char *)ip + (ip->ip_hl << 2));
633 sprintf(buf, "[TCP] %s:%d -> %s:%d",
634 src,
635 ntohs(tcphdr->th_sport),
636 dst,
637 ntohs(tcphdr->th_dport));
638 break;
640 case IPPROTO_UDP:
641 udphdr = (struct udphdr *)((char *)ip + (ip->ip_hl << 2));
642 sprintf(buf, "[UDP] %s:%d -> %s:%d",
643 src,
644 ntohs(udphdr->uh_sport),
645 dst,
646 ntohs(udphdr->uh_dport));
647 break;
649 case IPPROTO_ICMP:
650 icmphdr = (struct icmp *)((char *)ip + (ip->ip_hl << 2));
651 sprintf(buf, "[ICMP] %s -> %s %u(%u)",
652 src,
653 dst,
654 icmphdr->icmp_type,
655 icmphdr->icmp_code);
656 break;
658 default:
659 sprintf(buf, "[%d] %s -> %s ", ip->ip_p, src, dst);
660 break;
663 return buf;
666 static void
667 SetAliasAddressFromIfName(const char *ifn)
669 size_t needed;
670 int mib[6];
671 char *buf, *lim, *next;
672 struct if_msghdr *ifm;
673 struct ifa_msghdr *ifam;
674 struct sockaddr_dl *s_dl;
675 struct sockaddr_in *s_in;
677 mib[0] = CTL_NET;
678 mib[1] = PF_ROUTE;
679 mib[2] = 0;
680 mib[3] = AF_INET; /* Only IP addresses please */
681 mib[4] = NET_RT_IFLIST;
682 mib[5] = 0; /* ifIndex??? */
684 * Get interface data.
686 if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
687 err(1, "iflist-sysctl-estimate");
688 if ((buf = malloc(needed)) == NULL)
689 errx(1, "malloc failed");
690 if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
691 err(1, "iflist-sysctl-get");
692 lim = buf + needed;
694 * Loop through interfaces until one with
695 * given name is found. This is done to
696 * find correct interface index for routing
697 * message processing.
699 ifIndex = 0;
700 next = buf;
701 while (next < lim) {
702 ifm = (struct if_msghdr *)next;
703 next += ifm->ifm_msglen;
704 if (ifm->ifm_version != RTM_VERSION) {
705 if (verbose)
706 warnx("routing message version %d "
707 "not understood", ifm->ifm_version);
708 continue;
710 if (ifm->ifm_type == RTM_IFINFO) {
711 s_dl = (struct sockaddr_dl *)(ifm + 1);
712 if (strlen(ifn) == s_dl->sdl_nlen &&
713 strncmp(ifn, s_dl->sdl_data, s_dl->sdl_nlen) == 0) {
714 ifIndex = ifm->ifm_index;
715 ifMTU = ifm->ifm_data.ifi_mtu;
716 break;
720 if (!ifIndex)
721 errx(1, "unknown interface name %s", ifn);
723 * Get interface address.
725 s_in = NULL;
726 while (next < lim) {
727 ifam = (struct ifa_msghdr *)next;
728 next += ifam->ifam_msglen;
729 if (ifam->ifam_version != RTM_VERSION) {
730 if (verbose)
731 warnx("routing message version %d "
732 "not understood", ifam->ifam_version);
733 continue;
735 if (ifam->ifam_type != RTM_NEWADDR)
736 break;
737 if (ifam->ifam_addrs & RTA_IFA) {
738 int i;
739 char *cp = (char *)(ifam + 1);
741 #define ROUNDUP(a) \
742 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
743 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
745 for (i = 1; i < RTA_IFA; i <<= 1)
746 if (ifam->ifam_addrs & i)
747 ADVANCE(cp, (struct sockaddr *)cp);
748 if (((struct sockaddr *)cp)->sa_family == AF_INET) {
749 s_in = (struct sockaddr_in *)cp;
750 break;
754 if (s_in == NULL)
755 errx(1, "%s: cannot get interface address", ifn);
757 PacketAliasSetAddress(s_in->sin_addr);
758 syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes",
759 inet_ntoa(s_in->sin_addr), ifMTU);
761 free(buf);
764 void
765 Quit(const char *msg)
767 Warn(msg);
768 exit(1);
771 void
772 Warn(const char *msg)
774 if (background)
775 syslog(LOG_ALERT, "%s (%m)", msg);
776 else
777 warn("%s", msg);
780 static void
781 RefreshAddr(int sig __unused)
783 if (ifName)
784 assignAliasAddr = 1;
787 static void
788 InitiateShutdown(int sig __unused)
790 struct sigaction sa;
792 * Start timer to allow kernel gracefully
793 * shutdown existing connections when system
794 * is shut down.
796 sa.sa_handler = Shutdown;
797 sa.sa_flags = 0;
798 sigemptyset(&sa.sa_mask);
799 sigaction(SIGALRM, &sa, NULL);
800 alarm(10);
803 static void
804 Shutdown(int sig __unused)
806 running = 0;
810 * Different options recognized by this program.
813 enum Option {
814 PacketAliasOption,
815 Verbose,
816 InPort,
817 OutPort,
818 Port,
819 AliasAddress,
820 TargetAddress,
821 InterfaceName,
822 RedirectPort,
823 RedirectProto,
824 RedirectAddress,
825 ConfigFile,
826 DynamicMode,
827 ProxyRule,
828 LogDenied,
829 LogFacility,
830 PunchFW,
831 LogIpfwDenied
834 enum Param {
835 YesNo,
836 Numeric,
837 String,
838 None,
839 Address,
840 Service
844 * Option information structure (used by ParseOption).
847 struct OptionInfo {
848 enum Option type;
849 int packetAliasOpt;
850 enum Param parm;
851 const char* parmDescription;
852 const char* description;
853 const char* name;
854 const char* shortName;
858 * Table of known options.
861 static struct OptionInfo optionTable[] = {
862 { PacketAliasOption,
863 PKT_ALIAS_UNREGISTERED_ONLY,
864 YesNo,
865 "[yes|no]",
866 "alias only unregistered addresses",
867 "unregistered_only",
868 "u" },
870 { PacketAliasOption,
871 PKT_ALIAS_LOG,
872 YesNo,
873 "[yes|no]",
874 "enable logging",
875 "log",
876 "l" },
878 { PacketAliasOption,
879 PKT_ALIAS_PROXY_ONLY,
880 YesNo,
881 "[yes|no]",
882 "proxy only",
883 "proxy_only",
884 NULL },
886 { PacketAliasOption,
887 PKT_ALIAS_REVERSE,
888 YesNo,
889 "[yes|no]",
890 "operate in reverse mode",
891 "reverse",
892 NULL },
894 { PacketAliasOption,
895 PKT_ALIAS_DENY_INCOMING,
896 YesNo,
897 "[yes|no]",
898 "allow incoming connections",
899 "deny_incoming",
900 "d" },
902 { PacketAliasOption,
903 PKT_ALIAS_USE_SOCKETS,
904 YesNo,
905 "[yes|no]",
906 "use sockets to inhibit port conflict",
907 "use_sockets",
908 "s" },
910 { PacketAliasOption,
911 PKT_ALIAS_SAME_PORTS,
912 YesNo,
913 "[yes|no]",
914 "try to keep original port numbers for connections",
915 "same_ports",
916 "m" },
918 { Verbose,
920 YesNo,
921 "[yes|no]",
922 "verbose mode, dump packet information",
923 "verbose",
924 "v" },
926 { DynamicMode,
928 YesNo,
929 "[yes|no]",
930 "dynamic mode, automatically detect interface address changes",
931 "dynamic",
932 NULL },
934 { InPort,
936 Service,
937 "number|service_name",
938 "set port for incoming packets",
939 "in_port",
940 "i" },
942 { OutPort,
944 Service,
945 "number|service_name",
946 "set port for outgoing packets",
947 "out_port",
948 "o" },
950 { Port,
952 Service,
953 "number|service_name",
954 "set port (defaults to natd/divert)",
955 "port",
956 "p" },
958 { AliasAddress,
960 Address,
961 "x.x.x.x",
962 "address to use for aliasing",
963 "alias_address",
964 "a" },
966 { TargetAddress,
968 Address,
969 "x.x.x.x",
970 "address to use for incoming sessions",
971 "target_address",
972 "t" },
974 { InterfaceName,
976 String,
977 "network_if_name",
978 "take aliasing address from interface",
979 "interface",
980 "n" },
982 { ProxyRule,
984 String,
985 "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
986 "a.b.c.d:yyyy",
987 "add transparent proxying / destination NAT",
988 "proxy_rule",
989 NULL },
991 { RedirectPort,
993 String,
994 "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
995 " [remote_addr[:remote_port_range]]",
996 "redirect a port (or ports) for incoming traffic",
997 "redirect_port",
998 NULL },
1000 { RedirectProto,
1002 String,
1003 "proto local_addr [public_addr] [remote_addr]",
1004 "redirect packets of a given proto",
1005 "redirect_proto",
1006 NULL },
1008 { RedirectAddress,
1010 String,
1011 "local_addr[,...] public_addr",
1012 "define mapping between local and public addresses",
1013 "redirect_address",
1014 NULL },
1016 { ConfigFile,
1018 String,
1019 "file_name",
1020 "read options from configuration file",
1021 "config",
1022 "f" },
1024 { LogDenied,
1026 YesNo,
1027 "[yes|no]",
1028 "enable logging of denied incoming packets",
1029 "log_denied",
1030 NULL },
1032 { LogFacility,
1034 String,
1035 "facility",
1036 "name of syslog facility to use for logging",
1037 "log_facility",
1038 NULL },
1040 { PunchFW,
1042 String,
1043 "basenumber:count",
1044 "punch holes in the firewall for incoming FTP/IRC DCC connections",
1045 "punch_fw",
1046 NULL },
1048 { LogIpfwDenied,
1050 YesNo,
1051 "[yes|no]",
1052 "log packets converted by natd, but denied by ipfw",
1053 "log_ipfw_denied",
1054 NULL },
1057 static void
1058 ParseOption(const char *option, const char *parms)
1060 int i;
1061 struct OptionInfo* info;
1062 int yesNoValue;
1063 int aliasValue;
1064 int numValue;
1065 u_short uNumValue;
1066 const char* strValue;
1067 struct in_addr addrValue;
1068 int max;
1069 char* end;
1070 CODE* fac_record = NULL;
1072 * Find option from table.
1074 max = sizeof(optionTable) / sizeof(struct OptionInfo);
1075 for (i = 0, info = optionTable; i < max; i++, info++) {
1076 if (!strcmp(info->name, option))
1077 break;
1079 if (info->shortName)
1080 if (!strcmp(info->shortName, option))
1081 break;
1084 if (i >= max) {
1085 warnx("unknown option %s", option);
1086 Usage();
1089 uNumValue = 0;
1090 yesNoValue = 0;
1091 numValue = 0;
1092 strValue = NULL;
1094 * Check parameters.
1096 switch (info->parm) {
1097 case YesNo:
1098 if (!parms)
1099 parms = "yes";
1101 if (!strcmp(parms, "yes"))
1102 yesNoValue = 1;
1103 else
1104 if (!strcmp(parms, "no"))
1105 yesNoValue = 0;
1106 else
1107 errx(1, "%s needs yes/no parameter", option);
1108 break;
1110 case Service:
1111 if (!parms)
1112 errx(1, "%s needs service name or "
1113 "port number parameter",
1114 option);
1116 uNumValue = StrToPort(parms, "divert");
1117 break;
1119 case Numeric:
1120 if (parms)
1121 numValue = strtol(parms, &end, 10);
1122 else
1123 end = NULL;
1125 if (end == parms)
1126 errx(1, "%s needs numeric parameter", option);
1127 break;
1129 case String:
1130 strValue = parms;
1131 if (!strValue)
1132 errx(1, "%s needs parameter", option);
1133 break;
1135 case None:
1136 if (parms)
1137 errx(1, "%s does not take parameters", option);
1138 break;
1140 case Address:
1141 if (!parms)
1142 errx(1, "%s needs address/host parameter", option);
1144 StrToAddr(parms, &addrValue);
1145 break;
1148 switch (info->type) {
1149 case PacketAliasOption:
1151 aliasValue = yesNoValue ? info->packetAliasOpt : 0;
1152 PacketAliasSetMode(aliasValue, info->packetAliasOpt);
1153 break;
1155 case Verbose:
1156 verbose = yesNoValue;
1157 break;
1159 case DynamicMode:
1160 dynamicMode = yesNoValue;
1161 break;
1163 case InPort:
1164 inPort = uNumValue;
1165 break;
1167 case OutPort:
1168 outPort = uNumValue;
1169 break;
1171 case Port:
1172 inOutPort = uNumValue;
1173 break;
1175 case AliasAddress:
1176 memcpy(&aliasAddr, &addrValue, sizeof(struct in_addr));
1177 break;
1179 case TargetAddress:
1180 PacketAliasSetTarget(addrValue);
1181 break;
1183 case RedirectPort:
1184 SetupPortRedirect(strValue);
1185 break;
1187 case RedirectProto:
1188 SetupProtoRedirect(strValue);
1189 break;
1191 case RedirectAddress:
1192 SetupAddressRedirect(strValue);
1193 break;
1195 case ProxyRule:
1196 PacketAliasProxyRule(strValue);
1197 break;
1199 case InterfaceName:
1200 if (ifName)
1201 free(ifName);
1203 ifName = strdup(strValue);
1204 break;
1206 case ConfigFile:
1207 ReadConfigFile(strValue);
1208 break;
1210 case LogDenied:
1211 logDropped = yesNoValue;
1212 break;
1214 case LogFacility:
1216 fac_record = facilitynames;
1217 while (fac_record->c_name != NULL) {
1218 if (!strcmp(fac_record->c_name, strValue)) {
1219 logFacility = fac_record->c_val;
1220 break;
1222 } else
1223 fac_record++;
1226 if(fac_record->c_name == NULL)
1227 errx(1, "Unknown log facility name: %s", strValue);
1229 break;
1231 case PunchFW:
1232 SetupPunchFW(strValue);
1233 break;
1235 case LogIpfwDenied:
1236 logIpfwDenied = yesNoValue;
1237 break;
1241 void
1242 ReadConfigFile(const char *fileName)
1244 FILE* file;
1245 char *buf;
1246 size_t len;
1247 char *ptr, *p;
1248 char* option;
1250 file = fopen(fileName, "r");
1251 if (!file)
1252 err(1, "cannot open config file %s", fileName);
1254 while ((buf = fgetln(file, &len)) != NULL) {
1255 if (buf[len - 1] == '\n')
1256 buf[len - 1] = '\0';
1257 else
1258 errx(1, "config file format error: "
1259 "last line should end with newline");
1262 * Check for comments, strip off trailing spaces.
1264 if ((ptr = strchr(buf, '#')))
1265 *ptr = '\0';
1266 for (ptr = buf; isspace(*ptr); ++ptr)
1267 continue;
1268 if (*ptr == '\0')
1269 continue;
1270 for (p = strchr(buf, '\0'); isspace(*--p);)
1271 continue;
1272 *++p = '\0';
1275 * Extract option name.
1277 option = ptr;
1278 while (*ptr && !isspace(*ptr))
1279 ++ptr;
1281 if (*ptr != '\0') {
1282 *ptr = '\0';
1283 ++ptr;
1286 * Skip white space between name and parms.
1288 while (*ptr && isspace(*ptr))
1289 ++ptr;
1291 ParseOption(option, *ptr ? ptr : NULL);
1294 fclose(file);
1297 static void
1298 Usage(void)
1300 int i;
1301 int max;
1302 struct OptionInfo* info;
1304 fprintf(stderr, "Recognized options:\n\n");
1306 max = sizeof(optionTable) / sizeof(struct OptionInfo);
1307 for (i = 0, info = optionTable; i < max; i++, info++) {
1308 fprintf(stderr, "-%-20s %s\n", info->name,
1309 info->parmDescription);
1311 if (info->shortName)
1312 fprintf(stderr, "-%-20s %s\n", info->shortName,
1313 info->parmDescription);
1315 fprintf(stderr, " %s\n\n", info->description);
1318 exit(1);
1321 void
1322 SetupPortRedirect(const char *parms)
1324 char buf[128];
1325 char* ptr;
1326 char* serverPool;
1327 struct in_addr localAddr;
1328 struct in_addr publicAddr;
1329 struct in_addr remoteAddr;
1330 port_range portRange;
1331 u_short localPort = 0;
1332 u_short publicPort = 0;
1333 u_short remotePort = 0;
1334 u_short numLocalPorts = 0;
1335 u_short numPublicPorts = 0;
1336 u_short numRemotePorts = 0;
1337 int proto;
1338 char* protoName;
1339 char* separator;
1340 int i;
1341 struct alias_link *alink = NULL;
1343 strcpy(buf, parms);
1345 * Extract protocol.
1347 protoName = strtok(buf, " \t");
1348 if (!protoName)
1349 errx(1, "redirect_port: missing protocol");
1351 proto = StrToProto(protoName);
1353 * Extract local address.
1355 ptr = strtok(NULL, " \t");
1356 if (!ptr)
1357 errx(1, "redirect_port: missing local address");
1359 separator = strchr(ptr, ',');
1360 if (separator) { /* LSNAT redirection syntax. */
1361 localAddr.s_addr = INADDR_NONE;
1362 localPort = ~0;
1363 numLocalPorts = 1;
1364 serverPool = ptr;
1365 } else {
1366 if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0 )
1367 errx(1, "redirect_port: invalid local port range");
1369 localPort = GETLOPORT(portRange);
1370 numLocalPorts = GETNUMPORTS(portRange);
1371 serverPool = NULL;
1375 * Extract public port and optionally address.
1377 ptr = strtok(NULL, " \t");
1378 if (!ptr)
1379 errx(1, "redirect_port: missing public port");
1381 separator = strchr(ptr, ':');
1382 if (separator) {
1383 if (StrToAddrAndPortRange(ptr, &publicAddr, protoName, &portRange) != 0 )
1384 errx(1, "redirect_port: invalid public port range");
1385 } else {
1386 publicAddr.s_addr = INADDR_ANY;
1387 if (StrToPortRange(ptr, protoName, &portRange) != 0)
1388 errx(1, "redirect_port: invalid public port range");
1391 publicPort = GETLOPORT(portRange);
1392 numPublicPorts = GETNUMPORTS(portRange);
1395 * Extract remote address and optionally port.
1397 ptr = strtok(NULL, " \t");
1398 if (ptr) {
1399 separator = strchr(ptr, ':');
1400 if (separator) {
1401 if (StrToAddrAndPortRange(ptr, &remoteAddr, protoName, &portRange) != 0)
1402 errx(1, "redirect_port: invalid remote port range");
1403 } else {
1404 SETLOPORT(portRange, 0);
1405 SETNUMPORTS(portRange, 1);
1406 StrToAddr(ptr, &remoteAddr);
1408 } else {
1409 SETLOPORT(portRange, 0);
1410 SETNUMPORTS(portRange, 1);
1411 remoteAddr.s_addr = INADDR_ANY;
1414 remotePort = GETLOPORT(portRange);
1415 numRemotePorts = GETNUMPORTS(portRange);
1418 * Make sure port ranges match up, then add the redirect ports.
1420 if (numLocalPorts != numPublicPorts)
1421 errx(1, "redirect_port: port ranges must be equal in size");
1423 /* Remote port range is allowed to be '0' which means all ports. */
1424 if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0))
1425 errx(1, "redirect_port: remote port must be 0 or equal to local port range in size");
1427 for (i = 0 ; i < numPublicPorts ; ++i) {
1428 /* If remotePort is all ports, set it to 0. */
1429 u_short remotePortCopy = remotePort + i;
1430 if (numRemotePorts == 1 && remotePort == 0)
1431 remotePortCopy = 0;
1433 alink = PacketAliasRedirectPort(localAddr,
1434 htons(localPort + i),
1435 remoteAddr,
1436 htons(remotePortCopy),
1437 publicAddr,
1438 htons(publicPort + i),
1439 proto);
1443 * Setup LSNAT server pool.
1445 if (serverPool != NULL && alink != NULL) {
1446 ptr = strtok(serverPool, ",");
1447 while (ptr != NULL) {
1448 if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0)
1449 errx(1, "redirect_port: invalid local port range");
1451 localPort = GETLOPORT(portRange);
1452 if (GETNUMPORTS(portRange) != 1)
1453 errx(1, "redirect_port: local port must be single in this context");
1454 PacketAliasAddServer(alink, localAddr, htons(localPort));
1455 ptr = strtok(NULL, ",");
1460 void
1461 SetupProtoRedirect(const char *parms)
1463 char buf[128];
1464 char* ptr;
1465 struct in_addr localAddr;
1466 struct in_addr publicAddr;
1467 struct in_addr remoteAddr;
1468 int proto;
1469 char* protoName;
1470 struct protoent *protoent;
1472 strcpy(buf, parms);
1474 * Extract protocol.
1476 protoName = strtok(buf, " \t");
1477 if (!protoName)
1478 errx(1, "redirect_proto: missing protocol");
1480 protoent = getprotobyname(protoName);
1481 if (protoent == NULL)
1482 errx(1, "redirect_proto: unknown protocol %s", protoName);
1483 else
1484 proto = protoent->p_proto;
1486 * Extract local address.
1488 ptr = strtok(NULL, " \t");
1489 if (!ptr)
1490 errx(1, "redirect_proto: missing local address");
1491 else
1492 StrToAddr(ptr, &localAddr);
1494 * Extract optional public address.
1496 ptr = strtok(NULL, " \t");
1497 if (ptr)
1498 StrToAddr(ptr, &publicAddr);
1499 else
1500 publicAddr.s_addr = INADDR_ANY;
1502 * Extract optional remote address.
1504 ptr = strtok(NULL, " \t");
1505 if (ptr)
1506 StrToAddr(ptr, &remoteAddr);
1507 else
1508 remoteAddr.s_addr = INADDR_ANY;
1510 * Create aliasing link.
1512 PacketAliasRedirectProto(localAddr, remoteAddr, publicAddr, proto);
1515 void
1516 SetupAddressRedirect(const char *parms)
1518 char buf[128];
1519 char* ptr;
1520 char* separator;
1521 struct in_addr localAddr;
1522 struct in_addr publicAddr;
1523 char* serverPool;
1524 struct alias_link *alink;
1526 strcpy(buf, parms);
1528 * Extract local address.
1530 ptr = strtok(buf, " \t");
1531 if (!ptr)
1532 errx(1, "redirect_address: missing local address");
1534 separator = strchr(ptr, ',');
1535 if (separator) { /* LSNAT redirection syntax. */
1536 localAddr.s_addr = INADDR_NONE;
1537 serverPool = ptr;
1538 } else {
1539 StrToAddr(ptr, &localAddr);
1540 serverPool = NULL;
1543 * Extract public address.
1545 ptr = strtok(NULL, " \t");
1546 if (!ptr)
1547 errx(1, "redirect_address: missing public address");
1549 StrToAddr(ptr, &publicAddr);
1550 alink = PacketAliasRedirectAddr(localAddr, publicAddr);
1553 * Setup LSNAT server pool.
1555 if (serverPool != NULL && alink != NULL) {
1556 ptr = strtok(serverPool, ",");
1557 while (ptr != NULL) {
1558 StrToAddr(ptr, &localAddr);
1559 PacketAliasAddServer(alink, localAddr, htons(~0));
1560 ptr = strtok(NULL, ",");
1565 void
1566 StrToAddr(const char *str, struct in_addr *addr)
1568 struct hostent *hp;
1570 if (inet_aton(str, addr))
1571 return;
1573 hp = gethostbyname(str);
1574 if (!hp)
1575 errx(1, "unknown host %s", str);
1577 memcpy(addr, hp->h_addr, sizeof(struct in_addr));
1580 u_short
1581 StrToPort(const char *str, const char *proto)
1583 u_short port;
1584 struct servent* sp;
1585 char* end;
1587 port = strtol(str, &end, 10);
1588 if (end != str)
1589 return htons(port);
1591 sp = getservbyname(str, proto);
1592 if (!sp)
1593 errx(1, "unknown service %s/%s", str, proto);
1595 return sp->s_port;
1599 StrToPortRange(const char *str, const char *proto, port_range *portRange)
1601 char* sep;
1602 struct servent* sp;
1603 char* end;
1604 u_short loPort;
1605 u_short hiPort;
1607 /* First see if this is a service, return corresponding port if so. */
1608 sp = getservbyname(str,proto);
1609 if (sp) {
1610 SETLOPORT(*portRange, ntohs(sp->s_port));
1611 SETNUMPORTS(*portRange, 1);
1612 return 0;
1615 /* Not a service, see if it's a single port or port range. */
1616 sep = strchr(str, '-');
1617 if (sep == NULL) {
1618 SETLOPORT(*portRange, strtol(str, &end, 10));
1619 if (end != str) {
1620 /* Single port. */
1621 SETNUMPORTS(*portRange, 1);
1622 return 0;
1625 /* Error in port range field. */
1626 errx(1, "unknown service %s/%s", str, proto);
1629 /* Port range, get the values and sanity check. */
1630 sscanf(str, "%hu-%hu", &loPort, &hiPort);
1631 SETLOPORT(*portRange, loPort);
1632 SETNUMPORTS(*portRange, 0); /* Error by default */
1633 if (loPort <= hiPort)
1634 SETNUMPORTS(*portRange, hiPort - loPort + 1);
1636 if (GETNUMPORTS(*portRange) == 0)
1637 errx(1, "invalid port range %s", str);
1639 return 0;
1644 StrToProto(const char *str)
1646 if (!strcmp(str, "tcp"))
1647 return IPPROTO_TCP;
1649 if (!strcmp(str, "udp"))
1650 return IPPROTO_UDP;
1652 errx(1, "unknown protocol %s. Expected tcp or udp", str);
1656 StrToAddrAndPortRange(const char *str, struct in_addr *addr, char *proto, port_range *portRange)
1658 char* ptr;
1660 ptr = strchr(str, ':');
1661 if (!ptr)
1662 errx(1, "%s is missing port number", str);
1664 *ptr = '\0';
1665 ++ptr;
1667 StrToAddr(str, addr);
1668 return StrToPortRange(ptr, proto, portRange);
1671 static void
1672 SetupPunchFW(const char *strValue)
1674 unsigned int base, num;
1676 if (sscanf(strValue, "%u:%u", &base, &num) != 2)
1677 errx(1, "punch_fw: basenumber:count parameter required");
1679 PacketAliasSetFWBase(base, num);
1680 PacketAliasSetMode(PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);