kernel - Add mandatory config hooks delay
[dragonfly.git] / sbin / natd / natd.c
blob933120f9de3c387b8154b1a3f97c8f2d704ef82e
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 $
15 #define SYSLOG_NAMES
17 #include <sys/param.h>
18 #include <sys/socket.h>
19 #include <sys/sysctl.h>
20 #include <sys/time.h>
22 #include <netinet/in.h>
23 #include <netinet/in_systm.h>
24 #include <netinet/ip.h>
25 #include <netinet/tcp.h>
26 #include <netinet/udp.h>
27 #include <netinet/ip_icmp.h>
28 #include <net/if.h>
29 #include <net/if_dl.h>
30 #include <net/route.h>
31 #include <arpa/inet.h>
33 #include <alias.h>
34 #include <ctype.h>
35 #include <err.h>
36 #include <errno.h>
37 #include <netdb.h>
38 #include <signal.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <syslog.h>
43 #include <unistd.h>
45 #include "natd.h"
48 * Default values for input and output
49 * divert socket ports.
52 #define DEFAULT_SERVICE "natd"
55 * Definition of a port range, and macros to deal with values.
56 * FORMAT: HI 16-bits == first port in range, 0 == all ports.
57 * LO 16-bits == number of ports in range
58 * NOTES: - Port values are not stored in network byte order.
61 typedef u_long port_range;
63 #define GETLOPORT(x) ((x) >> 0x10)
64 #define GETNUMPORTS(x) ((x) & 0x0000ffff)
65 #define GETHIPORT(x) (GETLOPORT((x)) + GETNUMPORTS((x)))
67 /* Set y to be the low-port value in port_range variable x. */
68 #define SETLOPORT(x,y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
70 /* Set y to be the number of ports in port_range variable x. */
71 #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y))
74 * Function prototypes.
77 static void DoAliasing(int, int);
78 static void DaemonMode(void);
79 static void HandleRoutingInfo(int);
80 static void Usage(void);
81 static char* FormatPacket(struct ip *);
82 static void PrintPacket(struct ip *);
83 static void SyslogPacket(struct ip *, int, const char *);
84 static void SetAliasAddressFromIfName(const char *);
85 static void InitiateShutdown(int);
86 static void Shutdown(int);
87 static void RefreshAddr(int);
88 static void ParseOption(const char *, const char *);
89 static void ReadConfigFile(const char *);
90 static void SetupPortRedirect(const char *);
91 static void SetupProtoRedirect(const char *);
92 static void SetupAddressRedirect(const char *);
93 static void StrToAddr(const char *, struct in_addr *);
94 static u_short StrToPort(const char *, const char *);
95 static int StrToPortRange(const char *, const char *, port_range *);
96 static int StrToProto(const char *);
97 static int StrToAddrAndPortRange(const char *, struct in_addr *, char *, port_range *);
98 static void ParseArgs(int, char **);
99 static void SetupPunchFW(const char *);
102 * Globals.
105 static int verbose;
106 static int background;
107 static volatile sig_atomic_t running;
108 static volatile sig_atomic_t assignAliasAddr;
109 static char* ifName;
110 static int ifIndex;
111 static u_short inPort;
112 static u_short outPort;
113 static u_short inOutPort;
114 static struct in_addr aliasAddr;
115 static int dynamicMode;
116 static int ifMTU;
117 static int aliasOverhead;
118 static int icmpSock;
119 static int dropIgnoredIncoming;
120 static int logDropped;
121 static int logFacility;
122 static int logIpfwDenied;
123 static int exitDelay;
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;
160 exitDelay = EXIT_DELAY;
162 ParseArgs(argc, argv);
164 * Log ipfw(8) denied packets by default in verbose mode.
166 if (logIpfwDenied == -1)
167 logIpfwDenied = verbose;
169 * Open syslog channel.
171 openlog("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0),
172 logFacility);
174 * Check that valid aliasing address has been given.
176 if (aliasAddr.s_addr == INADDR_NONE && ifName == NULL)
177 errx(1, "aliasing address not given");
179 if (aliasAddr.s_addr != INADDR_NONE && ifName != NULL)
180 errx(1, "both alias address and interface "
181 "name are not allowed");
183 * Check that valid port number is known.
185 if (inPort != 0 || outPort != 0)
186 if (inPort == 0 || outPort == 0)
187 errx(1, "both input and output ports are required");
189 if (inPort == 0 && outPort == 0 && inOutPort == 0)
190 ParseOption("port", DEFAULT_SERVICE);
193 * Check if ignored packets should be dropped.
195 dropIgnoredIncoming = PacketAliasSetMode(0, 0);
196 dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING;
198 * Create divert sockets. Use only one socket if -p was specified
199 * on command line. Otherwise, create separate sockets for
200 * outgoing and incoming connnections.
202 if (inOutPort) {
203 divertInOut = socket(PF_INET, SOCK_RAW, IPPROTO_DIVERT);
204 if (divertInOut == -1)
205 Quit("Unable to create divert socket.");
207 divertIn = -1;
208 divertOut = -1;
210 * Bind socket.
213 addr.sin_family = AF_INET;
214 addr.sin_addr.s_addr = INADDR_ANY;
215 addr.sin_port = inOutPort;
217 if (bind(divertInOut,
218 (struct sockaddr *)&addr,
219 sizeof addr) == -1)
220 Quit("Unable to bind divert socket.");
221 } else {
222 divertIn = socket(PF_INET, SOCK_RAW, IPPROTO_DIVERT);
223 if (divertIn == -1)
224 Quit("Unable to create incoming divert socket.");
226 divertOut = socket(PF_INET, SOCK_RAW, IPPROTO_DIVERT);
227 if (divertOut == -1)
228 Quit("Unable to create outgoing divert socket.");
230 divertInOut = -1;
233 * Bind divert sockets.
236 addr.sin_family = AF_INET;
237 addr.sin_addr.s_addr = INADDR_ANY;
238 addr.sin_port = inPort;
240 if (bind(divertIn,
241 (struct sockaddr *)&addr,
242 sizeof addr) == -1)
243 Quit("Unable to bind incoming divert socket.");
245 addr.sin_family = AF_INET;
246 addr.sin_addr.s_addr = INADDR_ANY;
247 addr.sin_port = outPort;
249 if (bind(divertOut,
250 (struct sockaddr *)&addr,
251 sizeof addr) == -1)
252 Quit("Unable to bind outgoing divert socket.");
255 * Create routing socket if interface name specified and in dynamic mode.
257 routeSock = -1;
258 if (ifName) {
259 if (dynamicMode) {
260 routeSock = socket(PF_ROUTE, SOCK_RAW, 0);
261 if (routeSock == -1)
262 Quit("Unable to create routing info socket.");
264 assignAliasAddr = 1;
265 } else
266 SetAliasAddressFromIfName(ifName);
269 * Create socket for sending ICMP messages.
271 icmpSock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
272 if (icmpSock == -1)
273 Quit("Unable to create ICMP socket.");
276 * And disable reads for the socket, otherwise it slowly fills
277 * up with received icmps which we do not use.
279 shutdown(icmpSock, SHUT_RD);
282 * Become a daemon unless verbose mode was requested.
284 if (!verbose)
285 DaemonMode();
287 * Catch signals to manage shutdown and
288 * refresh of interface address.
290 sa.sa_flags = 0;
291 sigemptyset(&sa.sa_mask);
292 if (exitDelay)
293 sa.sa_handler = InitiateShutdown;
294 else
295 sa.sa_handler = Shutdown;
296 sigaction(SIGTERM, &sa, NULL);
297 sa.sa_handler = RefreshAddr;
298 sigaction(SIGHUP, &sa, NULL);
300 * Set alias address if it has been given.
302 if (aliasAddr.s_addr != INADDR_NONE)
303 PacketAliasSetAddress(aliasAddr);
305 * We need largest descriptor number for select.
308 fdMax = -1;
310 if (divertIn > fdMax)
311 fdMax = divertIn;
313 if (divertOut > fdMax)
314 fdMax = divertOut;
316 if (divertInOut > fdMax)
317 fdMax = divertInOut;
319 if (routeSock > fdMax)
320 fdMax = routeSock;
322 while (running) {
323 if (divertInOut != -1 && !ifName) {
325 * When using only one socket, just call
326 * DoAliasing repeatedly to process packets.
328 DoAliasing(divertInOut, DONT_KNOW);
329 continue;
332 * Build read mask from socket descriptors to select.
334 FD_ZERO(&readMask);
336 * Check if new packets are available.
338 if (divertIn != -1)
339 FD_SET(divertIn, &readMask);
341 if (divertOut != -1)
342 FD_SET(divertOut, &readMask);
344 if (divertInOut != -1)
345 FD_SET(divertInOut, &readMask);
347 * Routing info is processed always.
349 if (routeSock != -1)
350 FD_SET(routeSock, &readMask);
352 if (select(fdMax + 1,
353 &readMask,
354 NULL,
355 NULL,
356 NULL) == -1) {
357 if (errno == EINTR)
358 continue;
360 Quit("Select failed.");
363 if (divertIn != -1)
364 if (FD_ISSET(divertIn, &readMask))
365 DoAliasing(divertIn, INPUT);
367 if (divertOut != -1)
368 if (FD_ISSET(divertOut, &readMask))
369 DoAliasing(divertOut, OUTPUT);
371 if (divertInOut != -1)
372 if (FD_ISSET(divertInOut, &readMask))
373 DoAliasing(divertInOut, DONT_KNOW);
375 if (routeSock != -1)
376 if (FD_ISSET(routeSock, &readMask))
377 HandleRoutingInfo(routeSock);
380 if (background)
381 unlink(PIDFILE);
383 return 0;
386 static void
387 DaemonMode(void)
389 FILE* pidFile;
391 daemon(0, 0);
392 background = 1;
394 pidFile = fopen(PIDFILE, "w");
395 if (pidFile) {
396 fprintf(pidFile, "%d\n", getpid());
397 fclose(pidFile);
401 static void
402 ParseArgs(int argc, char **argv)
404 int arg;
405 char* opt;
406 char parmBuf[256];
407 int len; /* bounds checking */
409 for (arg = 1; arg < argc; arg++) {
410 opt = argv[arg];
411 if (*opt != '-') {
412 warnx("invalid option %s", opt);
413 Usage();
416 parmBuf[0] = '\0';
417 len = 0;
419 while (arg < argc - 1) {
420 if (argv[arg + 1][0] == '-')
421 break;
423 if (len) {
424 strncat(parmBuf, " ", sizeof(parmBuf) - (len + 1));
425 len += strlen(parmBuf + len);
428 ++arg;
429 strncat(parmBuf, argv[arg], sizeof(parmBuf) - (len + 1));
430 len += strlen(parmBuf + len);
434 ParseOption(opt + 1, (len ? parmBuf : NULL));
439 static void
440 DoAliasing(int fd, int direction)
442 int bytes;
443 int origBytes;
444 char buf[IP_MAXPACKET];
445 struct sockaddr_in addr;
446 int wrote;
447 int status;
448 int addrSize;
449 struct ip* ip;
450 char msgBuf[80];
452 if (assignAliasAddr) {
453 SetAliasAddressFromIfName(ifName);
454 assignAliasAddr = 0;
457 * Get packet from socket.
459 addrSize = sizeof addr;
460 origBytes = recvfrom(fd,
461 buf,
462 sizeof buf,
464 (struct sockaddr *)&addr,
465 &addrSize);
467 if (origBytes == -1) {
468 if (errno != EINTR)
469 Warn("read from divert socket failed");
471 return;
474 * This is a IP packet.
476 ip = (struct ip *)buf;
477 if (direction == DONT_KNOW) {
478 if (addr.sin_addr.s_addr == INADDR_ANY)
479 direction = OUTPUT;
480 else
481 direction = INPUT;
484 if (verbose) {
486 * Print packet direction and protocol type.
488 printf(direction == OUTPUT ? "Out " : "In ");
490 switch (ip->ip_p) {
491 case IPPROTO_TCP:
492 printf("[TCP] ");
493 break;
495 case IPPROTO_UDP:
496 printf("[UDP] ");
497 break;
499 case IPPROTO_ICMP:
500 printf("[ICMP] ");
501 break;
503 default:
504 printf("[%d] ", ip->ip_p);
505 break;
508 * Print addresses.
510 PrintPacket(ip);
513 if (direction == OUTPUT) {
515 * Outgoing packets. Do aliasing.
517 PacketAliasOut(buf, IP_MAXPACKET);
518 } else {
520 * Do aliasing.
522 status = PacketAliasIn(buf, IP_MAXPACKET);
523 if (status == PKT_ALIAS_IGNORED &&
524 dropIgnoredIncoming) {
525 if (verbose)
526 printf(" dropped.\n");
528 if (logDropped)
529 SyslogPacket(ip, LOG_WARNING, "denied");
531 return;
535 * Length might have changed during aliasing.
537 bytes = ntohs(ip->ip_len);
539 * Update alias overhead size for outgoing packets.
541 if (direction == OUTPUT &&
542 bytes - origBytes > aliasOverhead)
543 aliasOverhead = bytes - origBytes;
545 if (verbose) {
547 * Print addresses after aliasing.
549 printf(" aliased to\n");
550 printf(" ");
551 PrintPacket(ip);
552 printf("\n");
556 * Put packet back for processing.
558 wrote = sendto(fd,
559 buf,
560 bytes,
562 (struct sockaddr *)&addr,
563 sizeof addr);
565 if (wrote != bytes) {
566 if (errno == EMSGSIZE) {
567 if (direction == OUTPUT &&
568 ifMTU != -1)
569 SendNeedFragIcmp(icmpSock,
570 (struct ip *)buf,
571 ifMTU - aliasOverhead);
572 } else if (errno == EACCES && logIpfwDenied) {
573 sprintf(msgBuf, "failed to write packet back");
574 Warn(msgBuf);
579 static void
580 HandleRoutingInfo(int fd)
582 int bytes;
583 struct if_msghdr ifMsg;
585 * Get packet from socket.
587 bytes = read(fd, &ifMsg, sizeof ifMsg);
588 if (bytes == -1) {
589 Warn("read from routing socket failed");
590 return;
593 if (ifMsg.ifm_version != RTM_VERSION) {
594 Warn("unexpected packet read from routing socket");
595 return;
598 if (verbose)
599 printf("Routing message %#x received.\n", ifMsg.ifm_type);
601 if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO) &&
602 ifMsg.ifm_index == ifIndex) {
603 if (verbose)
604 printf("Interface address/MTU has probably changed.\n");
605 assignAliasAddr = 1;
609 static void
610 PrintPacket(struct ip *ip)
612 printf("%s", FormatPacket(ip));
615 static void
616 SyslogPacket(struct ip *ip, int priority, const char *label)
618 syslog(priority, "%s %s", label, FormatPacket(ip));
621 static char*
622 FormatPacket(struct ip *ip)
624 static char buf[256];
625 struct tcphdr* tcphdr;
626 struct udphdr* udphdr;
627 struct icmp* icmphdr;
628 char src[20];
629 char dst[20];
631 strcpy(src, inet_ntoa(ip->ip_src));
632 strcpy(dst, inet_ntoa(ip->ip_dst));
634 switch (ip->ip_p) {
635 case IPPROTO_TCP:
636 tcphdr = (struct tcphdr *)((char *)ip + (ip->ip_hl << 2));
637 sprintf(buf, "[TCP] %s:%d -> %s:%d",
638 src,
639 ntohs(tcphdr->th_sport),
640 dst,
641 ntohs(tcphdr->th_dport));
642 break;
644 case IPPROTO_UDP:
645 udphdr = (struct udphdr *)((char *)ip + (ip->ip_hl << 2));
646 sprintf(buf, "[UDP] %s:%d -> %s:%d",
647 src,
648 ntohs(udphdr->uh_sport),
649 dst,
650 ntohs(udphdr->uh_dport));
651 break;
653 case IPPROTO_ICMP:
654 icmphdr = (struct icmp *)((char *)ip + (ip->ip_hl << 2));
655 sprintf(buf, "[ICMP] %s -> %s %u(%u)",
656 src,
657 dst,
658 icmphdr->icmp_type,
659 icmphdr->icmp_code);
660 break;
662 default:
663 sprintf(buf, "[%d] %s -> %s ", ip->ip_p, src, dst);
664 break;
667 return buf;
670 static void
671 SetAliasAddressFromIfName(const char *ifn)
673 size_t needed;
674 int mib[6];
675 char *buf, *lim, *next;
676 struct if_msghdr *ifm;
677 struct ifa_msghdr *ifam;
678 struct sockaddr_dl *s_dl;
679 struct sockaddr_in *s_in;
681 mib[0] = CTL_NET;
682 mib[1] = PF_ROUTE;
683 mib[2] = 0;
684 mib[3] = AF_INET; /* Only IP addresses please */
685 mib[4] = NET_RT_IFLIST;
686 mib[5] = 0; /* ifIndex??? */
688 * Get interface data.
690 if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
691 err(1, "iflist-sysctl-estimate");
692 if ((buf = malloc(needed)) == NULL)
693 errx(1, "malloc failed");
694 if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
695 err(1, "iflist-sysctl-get");
696 lim = buf + needed;
698 * Loop through interfaces until one with
699 * given name is found. This is done to
700 * find correct interface index for routing
701 * message processing.
703 ifIndex = 0;
704 next = buf;
705 while (next < lim) {
706 ifm = (struct if_msghdr *)next;
707 next += ifm->ifm_msglen;
708 if (ifm->ifm_version != RTM_VERSION) {
709 if (verbose)
710 warnx("routing message version %d "
711 "not understood", ifm->ifm_version);
712 continue;
714 if (ifm->ifm_type == RTM_IFINFO) {
715 s_dl = (struct sockaddr_dl *)(ifm + 1);
716 if (strlen(ifn) == s_dl->sdl_nlen &&
717 strncmp(ifn, s_dl->sdl_data, s_dl->sdl_nlen) == 0) {
718 ifIndex = ifm->ifm_index;
719 ifMTU = ifm->ifm_data.ifi_mtu;
720 break;
724 if (!ifIndex)
725 errx(1, "unknown interface name %s", ifn);
727 * Get interface address.
729 s_in = NULL;
730 while (next < lim) {
731 ifam = (struct ifa_msghdr *)next;
732 next += ifam->ifam_msglen;
733 if (ifam->ifam_version != RTM_VERSION) {
734 if (verbose)
735 warnx("routing message version %d "
736 "not understood", ifam->ifam_version);
737 continue;
739 if (ifam->ifam_type != RTM_NEWADDR)
740 break;
741 if (ifam->ifam_addrs & RTA_IFA) {
742 int i;
743 char *cp = (char *)(ifam + 1);
745 #define ROUNDUP(a) \
746 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
747 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
749 for (i = 1; i < RTA_IFA; i <<= 1)
750 if (ifam->ifam_addrs & i)
751 ADVANCE(cp, (struct sockaddr *)cp);
752 if (((struct sockaddr *)cp)->sa_family == AF_INET) {
753 s_in = (struct sockaddr_in *)cp;
754 break;
758 if (s_in == NULL)
759 errx(1, "%s: cannot get interface address", ifn);
761 PacketAliasSetAddress(s_in->sin_addr);
762 syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes",
763 inet_ntoa(s_in->sin_addr), ifMTU);
765 free(buf);
768 void
769 Quit(const char *msg)
771 Warn(msg);
772 exit(1);
775 void
776 Warn(const char *msg)
778 if (background)
779 syslog(LOG_ALERT, "%s (%m)", msg);
780 else
781 warn("%s", msg);
784 static void
785 RefreshAddr(int sig __unused)
787 if (ifName)
788 assignAliasAddr = 1;
791 static void
792 InitiateShutdown(int sig __unused)
794 struct sigaction sa;
796 * Start timer to allow kernel gracefully
797 * shutdown existing connections when system
798 * is shut down.
800 sa.sa_handler = Shutdown;
801 sa.sa_flags = 0;
802 sigemptyset(&sa.sa_mask);
803 sigaction(SIGALRM, &sa, NULL);
804 ualarm(exitDelay*1000, 1000);
807 static void
808 Shutdown(int sig __unused)
810 running = 0;
814 * Different options recognized by this program.
817 enum Option {
818 PacketAliasOption,
819 Verbose,
820 InPort,
821 OutPort,
822 Port,
823 AliasAddress,
824 TargetAddress,
825 InterfaceName,
826 RedirectPort,
827 RedirectProto,
828 RedirectAddress,
829 ConfigFile,
830 DynamicMode,
831 ProxyRule,
832 LogDenied,
833 LogFacility,
834 PunchFW,
835 LogIpfwDenied,
836 ExitDelay
839 enum Param {
840 YesNo,
841 Numeric,
842 String,
843 None,
844 Address,
845 Service
849 * Option information structure (used by ParseOption).
852 struct OptionInfo {
853 enum Option type;
854 int packetAliasOpt;
855 enum Param parm;
856 const char* parmDescription;
857 const char* description;
858 const char* name;
859 const char* shortName;
863 * Table of known options.
866 static struct OptionInfo optionTable[] = {
867 { PacketAliasOption,
868 PKT_ALIAS_UNREGISTERED_ONLY,
869 YesNo,
870 "[yes|no]",
871 "alias only unregistered addresses",
872 "unregistered_only",
873 "u" },
875 { PacketAliasOption,
876 PKT_ALIAS_LOG,
877 YesNo,
878 "[yes|no]",
879 "enable logging",
880 "log",
881 "l" },
883 { PacketAliasOption,
884 PKT_ALIAS_PROXY_ONLY,
885 YesNo,
886 "[yes|no]",
887 "proxy only",
888 "proxy_only",
889 NULL },
891 { PacketAliasOption,
892 PKT_ALIAS_REVERSE,
893 YesNo,
894 "[yes|no]",
895 "operate in reverse mode",
896 "reverse",
897 NULL },
899 { PacketAliasOption,
900 PKT_ALIAS_DENY_INCOMING,
901 YesNo,
902 "[yes|no]",
903 "allow incoming connections",
904 "deny_incoming",
905 "d" },
907 { PacketAliasOption,
908 PKT_ALIAS_USE_SOCKETS,
909 YesNo,
910 "[yes|no]",
911 "use sockets to inhibit port conflict",
912 "use_sockets",
913 "s" },
915 { PacketAliasOption,
916 PKT_ALIAS_SAME_PORTS,
917 YesNo,
918 "[yes|no]",
919 "try to keep original port numbers for connections",
920 "same_ports",
921 "m" },
923 { Verbose,
925 YesNo,
926 "[yes|no]",
927 "verbose mode, dump packet information",
928 "verbose",
929 "v" },
931 { DynamicMode,
933 YesNo,
934 "[yes|no]",
935 "dynamic mode, automatically detect interface address changes",
936 "dynamic",
937 NULL },
939 { InPort,
941 Service,
942 "number|service_name",
943 "set port for incoming packets",
944 "in_port",
945 "i" },
947 { OutPort,
949 Service,
950 "number|service_name",
951 "set port for outgoing packets",
952 "out_port",
953 "o" },
955 { Port,
957 Service,
958 "number|service_name",
959 "set port (defaults to natd/divert)",
960 "port",
961 "p" },
963 { AliasAddress,
965 Address,
966 "x.x.x.x",
967 "address to use for aliasing",
968 "alias_address",
969 "a" },
971 { TargetAddress,
973 Address,
974 "x.x.x.x",
975 "address to use for incoming sessions",
976 "target_address",
977 "t" },
979 { InterfaceName,
981 String,
982 "network_if_name",
983 "take aliasing address from interface",
984 "interface",
985 "n" },
987 { ProxyRule,
989 String,
990 "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
991 "a.b.c.d:yyyy",
992 "add transparent proxying / destination NAT",
993 "proxy_rule",
994 NULL },
996 { RedirectPort,
998 String,
999 "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
1000 " [remote_addr[:remote_port_range]]",
1001 "redirect a port (or ports) for incoming traffic",
1002 "redirect_port",
1003 NULL },
1005 { RedirectProto,
1007 String,
1008 "proto local_addr [public_addr] [remote_addr]",
1009 "redirect packets of a given proto",
1010 "redirect_proto",
1011 NULL },
1013 { RedirectAddress,
1015 String,
1016 "local_addr[,...] public_addr",
1017 "define mapping between local and public addresses",
1018 "redirect_address",
1019 NULL },
1021 { ConfigFile,
1023 String,
1024 "file_name",
1025 "read options from configuration file",
1026 "config",
1027 "f" },
1029 { LogDenied,
1031 YesNo,
1032 "[yes|no]",
1033 "enable logging of denied incoming packets",
1034 "log_denied",
1035 NULL },
1037 { LogFacility,
1039 String,
1040 "facility",
1041 "name of syslog facility to use for logging",
1042 "log_facility",
1043 NULL },
1045 { PunchFW,
1047 String,
1048 "basenumber:count",
1049 "punch holes in the firewall for incoming FTP/IRC DCC connections",
1050 "punch_fw",
1051 NULL },
1053 { LogIpfwDenied,
1055 YesNo,
1056 "[yes|no]",
1057 "log packets converted by natd, but denied by ipfw",
1058 "log_ipfw_denied",
1059 NULL },
1060 { ExitDelay,
1062 Numeric,
1063 "ms",
1064 "delay in ms before daemon exit after signal",
1065 "exit_delay",
1066 NULL },
1069 static void
1070 ParseOption(const char *option, const char *parms)
1072 int i;
1073 struct OptionInfo* info;
1074 int yesNoValue;
1075 int aliasValue;
1076 int numValue;
1077 u_short uNumValue;
1078 const char* strValue;
1079 struct in_addr addrValue;
1080 int max;
1081 char* end;
1082 CODE* fac_record = NULL;
1084 * Find option from table.
1086 max = sizeof(optionTable) / sizeof(struct OptionInfo);
1087 for (i = 0, info = optionTable; i < max; i++, info++) {
1088 if (!strcmp(info->name, option))
1089 break;
1091 if (info->shortName)
1092 if (!strcmp(info->shortName, option))
1093 break;
1096 if (i >= max) {
1097 warnx("unknown option %s", option);
1098 Usage();
1101 uNumValue = 0;
1102 yesNoValue = 0;
1103 numValue = 0;
1104 strValue = NULL;
1106 * Check parameters.
1108 switch (info->parm) {
1109 case YesNo:
1110 if (!parms)
1111 parms = "yes";
1113 if (!strcmp(parms, "yes"))
1114 yesNoValue = 1;
1115 else
1116 if (!strcmp(parms, "no"))
1117 yesNoValue = 0;
1118 else
1119 errx(1, "%s needs yes/no parameter", option);
1120 break;
1122 case Service:
1123 if (!parms)
1124 errx(1, "%s needs service name or "
1125 "port number parameter",
1126 option);
1128 uNumValue = StrToPort(parms, "divert");
1129 break;
1131 case Numeric:
1132 if (parms)
1133 numValue = strtol(parms, &end, 10);
1134 else
1135 end = NULL;
1137 if (end == parms)
1138 errx(1, "%s needs numeric parameter", option);
1139 break;
1141 case String:
1142 strValue = parms;
1143 if (!strValue)
1144 errx(1, "%s needs parameter", option);
1145 break;
1147 case None:
1148 if (parms)
1149 errx(1, "%s does not take parameters", option);
1150 break;
1152 case Address:
1153 if (!parms)
1154 errx(1, "%s needs address/host parameter", option);
1156 StrToAddr(parms, &addrValue);
1157 break;
1160 switch (info->type) {
1161 case PacketAliasOption:
1163 aliasValue = yesNoValue ? info->packetAliasOpt : 0;
1164 PacketAliasSetMode(aliasValue, info->packetAliasOpt);
1165 break;
1167 case Verbose:
1168 verbose = yesNoValue;
1169 break;
1171 case DynamicMode:
1172 dynamicMode = yesNoValue;
1173 break;
1175 case InPort:
1176 inPort = uNumValue;
1177 break;
1179 case OutPort:
1180 outPort = uNumValue;
1181 break;
1183 case Port:
1184 inOutPort = uNumValue;
1185 break;
1187 case AliasAddress:
1188 memcpy(&aliasAddr, &addrValue, sizeof(struct in_addr));
1189 break;
1191 case TargetAddress:
1192 PacketAliasSetTarget(addrValue);
1193 break;
1195 case RedirectPort:
1196 SetupPortRedirect(strValue);
1197 break;
1199 case RedirectProto:
1200 SetupProtoRedirect(strValue);
1201 break;
1203 case RedirectAddress:
1204 SetupAddressRedirect(strValue);
1205 break;
1207 case ProxyRule:
1208 PacketAliasProxyRule(strValue);
1209 break;
1211 case InterfaceName:
1212 if (ifName)
1213 free(ifName);
1215 ifName = strdup(strValue);
1216 break;
1218 case ConfigFile:
1219 ReadConfigFile(strValue);
1220 break;
1222 case LogDenied:
1223 logDropped = yesNoValue;
1224 break;
1226 case LogFacility:
1228 fac_record = facilitynames;
1229 while (fac_record->c_name != NULL) {
1230 if (!strcmp(fac_record->c_name, strValue)) {
1231 logFacility = fac_record->c_val;
1232 break;
1234 } else
1235 fac_record++;
1238 if(fac_record->c_name == NULL)
1239 errx(1, "Unknown log facility name: %s", strValue);
1241 break;
1243 case PunchFW:
1244 SetupPunchFW(strValue);
1245 break;
1247 case LogIpfwDenied:
1248 logIpfwDenied = yesNoValue;
1249 break;
1250 case ExitDelay:
1251 if (numValue < 0 || numValue > MAX_EXIT_DELAY)
1252 errx(1, "Incorrect exit delay: %d", numValue);
1253 exitDelay = numValue;
1254 break;
1258 void
1259 ReadConfigFile(const char *fileName)
1261 FILE* file;
1262 char *buf;
1263 size_t len;
1264 char *ptr, *p;
1265 char* option;
1267 file = fopen(fileName, "r");
1268 if (!file)
1269 err(1, "cannot open config file %s", fileName);
1271 while ((buf = fgetln(file, &len)) != NULL) {
1272 if (buf[len - 1] == '\n')
1273 buf[len - 1] = '\0';
1274 else
1275 errx(1, "config file format error: "
1276 "last line should end with newline");
1279 * Check for comments, strip off trailing spaces.
1281 if ((ptr = strchr(buf, '#')))
1282 *ptr = '\0';
1283 for (ptr = buf; isspace(*ptr); ++ptr)
1284 continue;
1285 if (*ptr == '\0')
1286 continue;
1287 for (p = strchr(buf, '\0'); isspace(*--p);)
1288 continue;
1289 *++p = '\0';
1292 * Extract option name.
1294 option = ptr;
1295 while (*ptr && !isspace(*ptr))
1296 ++ptr;
1298 if (*ptr != '\0') {
1299 *ptr = '\0';
1300 ++ptr;
1303 * Skip white space between name and parms.
1305 while (*ptr && isspace(*ptr))
1306 ++ptr;
1308 ParseOption(option, *ptr ? ptr : NULL);
1311 fclose(file);
1314 static void
1315 Usage(void)
1317 int i;
1318 int max;
1319 struct OptionInfo* info;
1321 fprintf(stderr, "Recognized options:\n\n");
1323 max = sizeof(optionTable) / sizeof(struct OptionInfo);
1324 for (i = 0, info = optionTable; i < max; i++, info++) {
1325 fprintf(stderr, "-%-20s %s\n", info->name,
1326 info->parmDescription);
1328 if (info->shortName)
1329 fprintf(stderr, "-%-20s %s\n", info->shortName,
1330 info->parmDescription);
1332 fprintf(stderr, " %s\n\n", info->description);
1335 exit(1);
1338 void
1339 SetupPortRedirect(const char *parms)
1341 char buf[128];
1342 char* ptr;
1343 char* serverPool;
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 struct alias_link *alink = NULL;
1360 strcpy(buf, parms);
1362 * Extract protocol.
1364 protoName = strtok(buf, " \t");
1365 if (!protoName)
1366 errx(1, "redirect_port: missing protocol");
1368 proto = StrToProto(protoName);
1370 * Extract local address.
1372 ptr = strtok(NULL, " \t");
1373 if (!ptr)
1374 errx(1, "redirect_port: missing local address");
1376 separator = strchr(ptr, ',');
1377 if (separator) { /* LSNAT redirection syntax. */
1378 localAddr.s_addr = INADDR_NONE;
1379 localPort = ~0;
1380 numLocalPorts = 1;
1381 serverPool = ptr;
1382 } else {
1383 if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0 )
1384 errx(1, "redirect_port: invalid local port range");
1386 localPort = GETLOPORT(portRange);
1387 numLocalPorts = GETNUMPORTS(portRange);
1388 serverPool = NULL;
1392 * Extract public port and optionally address.
1394 ptr = strtok(NULL, " \t");
1395 if (!ptr)
1396 errx(1, "redirect_port: missing public port");
1398 separator = strchr(ptr, ':');
1399 if (separator) {
1400 if (StrToAddrAndPortRange(ptr, &publicAddr, protoName, &portRange) != 0 )
1401 errx(1, "redirect_port: invalid public port range");
1402 } else {
1403 publicAddr.s_addr = INADDR_ANY;
1404 if (StrToPortRange(ptr, protoName, &portRange) != 0)
1405 errx(1, "redirect_port: invalid public port range");
1408 publicPort = GETLOPORT(portRange);
1409 numPublicPorts = GETNUMPORTS(portRange);
1412 * Extract remote address and optionally port.
1414 ptr = strtok(NULL, " \t");
1415 if (ptr) {
1416 separator = strchr(ptr, ':');
1417 if (separator) {
1418 if (StrToAddrAndPortRange(ptr, &remoteAddr, protoName, &portRange) != 0)
1419 errx(1, "redirect_port: invalid remote port range");
1420 } else {
1421 SETLOPORT(portRange, 0);
1422 SETNUMPORTS(portRange, 1);
1423 StrToAddr(ptr, &remoteAddr);
1425 } else {
1426 SETLOPORT(portRange, 0);
1427 SETNUMPORTS(portRange, 1);
1428 remoteAddr.s_addr = INADDR_ANY;
1431 remotePort = GETLOPORT(portRange);
1432 numRemotePorts = GETNUMPORTS(portRange);
1435 * Make sure port ranges match up, then add the redirect ports.
1437 if (numLocalPorts != numPublicPorts)
1438 errx(1, "redirect_port: port ranges must be equal in size");
1440 /* Remote port range is allowed to be '0' which means all ports. */
1441 if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0))
1442 errx(1, "redirect_port: remote port must be 0 or equal to local port range in size");
1444 for (i = 0 ; i < numPublicPorts ; ++i) {
1445 /* If remotePort is all ports, set it to 0. */
1446 u_short remotePortCopy = remotePort + i;
1447 if (numRemotePorts == 1 && remotePort == 0)
1448 remotePortCopy = 0;
1450 alink = PacketAliasRedirectPort(localAddr,
1451 htons(localPort + i),
1452 remoteAddr,
1453 htons(remotePortCopy),
1454 publicAddr,
1455 htons(publicPort + i),
1456 proto);
1460 * Setup LSNAT server pool.
1462 if (serverPool != NULL && alink != NULL) {
1463 ptr = strtok(serverPool, ",");
1464 while (ptr != NULL) {
1465 if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0)
1466 errx(1, "redirect_port: invalid local port range");
1468 localPort = GETLOPORT(portRange);
1469 if (GETNUMPORTS(portRange) != 1)
1470 errx(1, "redirect_port: local port must be single in this context");
1471 PacketAliasAddServer(alink, localAddr, htons(localPort));
1472 ptr = strtok(NULL, ",");
1477 void
1478 SetupProtoRedirect(const char *parms)
1480 char buf[128];
1481 char* ptr;
1482 struct in_addr localAddr;
1483 struct in_addr publicAddr;
1484 struct in_addr remoteAddr;
1485 int proto;
1486 char* protoName;
1487 struct protoent *protoent;
1489 strcpy(buf, parms);
1491 * Extract protocol.
1493 protoName = strtok(buf, " \t");
1494 if (!protoName)
1495 errx(1, "redirect_proto: missing protocol");
1497 protoent = getprotobyname(protoName);
1498 if (protoent == NULL)
1499 errx(1, "redirect_proto: unknown protocol %s", protoName);
1500 else
1501 proto = protoent->p_proto;
1503 * Extract local address.
1505 ptr = strtok(NULL, " \t");
1506 if (!ptr)
1507 errx(1, "redirect_proto: missing local address");
1508 else
1509 StrToAddr(ptr, &localAddr);
1511 * Extract optional public address.
1513 ptr = strtok(NULL, " \t");
1514 if (ptr)
1515 StrToAddr(ptr, &publicAddr);
1516 else
1517 publicAddr.s_addr = INADDR_ANY;
1519 * Extract optional remote address.
1521 ptr = strtok(NULL, " \t");
1522 if (ptr)
1523 StrToAddr(ptr, &remoteAddr);
1524 else
1525 remoteAddr.s_addr = INADDR_ANY;
1527 * Create aliasing link.
1529 PacketAliasRedirectProto(localAddr, remoteAddr, publicAddr, proto);
1532 void
1533 SetupAddressRedirect(const char *parms)
1535 char buf[128];
1536 char* ptr;
1537 char* separator;
1538 struct in_addr localAddr;
1539 struct in_addr publicAddr;
1540 char* serverPool;
1541 struct alias_link *alink;
1543 strcpy(buf, parms);
1545 * Extract local address.
1547 ptr = strtok(buf, " \t");
1548 if (!ptr)
1549 errx(1, "redirect_address: missing local address");
1551 separator = strchr(ptr, ',');
1552 if (separator) { /* LSNAT redirection syntax. */
1553 localAddr.s_addr = INADDR_NONE;
1554 serverPool = ptr;
1555 } else {
1556 StrToAddr(ptr, &localAddr);
1557 serverPool = NULL;
1560 * Extract public address.
1562 ptr = strtok(NULL, " \t");
1563 if (!ptr)
1564 errx(1, "redirect_address: missing public address");
1566 StrToAddr(ptr, &publicAddr);
1567 alink = PacketAliasRedirectAddr(localAddr, publicAddr);
1570 * Setup LSNAT server pool.
1572 if (serverPool != NULL && alink != NULL) {
1573 ptr = strtok(serverPool, ",");
1574 while (ptr != NULL) {
1575 StrToAddr(ptr, &localAddr);
1576 PacketAliasAddServer(alink, localAddr, htons(~0));
1577 ptr = strtok(NULL, ",");
1582 void
1583 StrToAddr(const char *str, struct in_addr *addr)
1585 struct hostent *hp;
1587 if (inet_aton(str, addr))
1588 return;
1590 hp = gethostbyname(str);
1591 if (!hp)
1592 errx(1, "unknown host %s", str);
1594 memcpy(addr, hp->h_addr, sizeof(struct in_addr));
1597 u_short
1598 StrToPort(const char *str, const char *proto)
1600 u_short port;
1601 struct servent* sp;
1602 char* end;
1604 port = strtol(str, &end, 10);
1605 if (end != str)
1606 return htons(port);
1608 sp = getservbyname(str, proto);
1609 if (!sp)
1610 errx(1, "unknown service %s/%s", str, proto);
1612 return sp->s_port;
1616 StrToPortRange(const char *str, const char *proto, port_range *portRange)
1618 char* sep;
1619 struct servent* sp;
1620 char* end;
1621 u_short loPort;
1622 u_short hiPort;
1624 /* First see if this is a service, return corresponding port if so. */
1625 sp = getservbyname(str,proto);
1626 if (sp) {
1627 SETLOPORT(*portRange, ntohs(sp->s_port));
1628 SETNUMPORTS(*portRange, 1);
1629 return 0;
1632 /* Not a service, see if it's a single port or port range. */
1633 sep = strchr(str, '-');
1634 if (sep == NULL) {
1635 SETLOPORT(*portRange, strtol(str, &end, 10));
1636 if (end != str) {
1637 /* Single port. */
1638 SETNUMPORTS(*portRange, 1);
1639 return 0;
1642 /* Error in port range field. */
1643 errx(1, "unknown service %s/%s", str, proto);
1646 /* Port range, get the values and sanity check. */
1647 sscanf(str, "%hu-%hu", &loPort, &hiPort);
1648 SETLOPORT(*portRange, loPort);
1649 SETNUMPORTS(*portRange, 0); /* Error by default */
1650 if (loPort <= hiPort)
1651 SETNUMPORTS(*portRange, hiPort - loPort + 1);
1653 if (GETNUMPORTS(*portRange) == 0)
1654 errx(1, "invalid port range %s", str);
1656 return 0;
1661 StrToProto(const char *str)
1663 if (!strcmp(str, "tcp"))
1664 return IPPROTO_TCP;
1666 if (!strcmp(str, "udp"))
1667 return IPPROTO_UDP;
1669 errx(1, "unknown protocol %s. Expected tcp or udp", str);
1673 StrToAddrAndPortRange(const char *str, struct in_addr *addr, char *proto, port_range *portRange)
1675 char* ptr;
1677 ptr = strchr(str, ':');
1678 if (!ptr)
1679 errx(1, "%s is missing port number", str);
1681 *ptr = '\0';
1682 ++ptr;
1684 StrToAddr(str, addr);
1685 return StrToPortRange(ptr, proto, portRange);
1688 static void
1689 SetupPunchFW(const char *strValue)
1691 unsigned int base, num;
1693 if (sscanf(strValue, "%u:%u", &base, &num) != 2)
1694 errx(1, "punch_fw: basenumber:count parameter required");
1696 PacketAliasSetFWBase(base, num);
1697 PacketAliasSetMode(PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);