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>
13 #include <sys/cdefs.h>
14 __FBSDID("$FreeBSD$");
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <sys/sysctl.h>
22 #include <sys/queue.h>
24 #include <netinet/in.h>
25 #include <netinet/in_systm.h>
26 #include <netinet/ip.h>
27 #include <netinet/tcp.h>
28 #include <netinet/udp.h>
29 #include <netinet/ip_icmp.h>
31 #include <net/if_dl.h>
32 #include <net/route.h>
33 #include <arpa/inet.h>
52 LIST_ENTRY(instance) list;
61 struct in_addr aliasAddr;
64 int dropIgnoredIncoming;
70 static LIST_HEAD(, instance) root = LIST_HEAD_INITIALIZER(root);
73 static struct instance *mip;
74 static int ninstance = 1;
77 * Default values for input and output
78 * divert socket ports.
81 #define DEFAULT_SERVICE "natd"
84 * Definition of a port range, and macros to deal with values.
85 * FORMAT: HI 16-bits == first port in range, 0 == all ports.
86 * LO 16-bits == number of ports in range
87 * NOTES: - Port values are not stored in network byte order.
90 typedef u_long port_range;
92 #define GETLOPORT(x) ((x) >> 0x10)
93 #define GETNUMPORTS(x) ((x) & 0x0000ffff)
94 #define GETHIPORT(x) (GETLOPORT((x)) + GETNUMPORTS((x)))
96 /* Set y to be the low-port value in port_range variable x. */
97 #define SETLOPORT(x,y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
99 /* Set y to be the number of ports in port_range variable x. */
100 #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y))
103 * Function prototypes.
106 static void DoAliasing (int fd, int direction);
107 static void DaemonMode (void);
108 static void HandleRoutingInfo (int fd);
109 static void Usage (void);
110 static char* FormatPacket (struct ip*);
111 static void PrintPacket (struct ip*);
112 static void SyslogPacket (struct ip*, int priority, const char *label);
113 static int SetAliasAddressFromIfName (const char *ifName);
114 static void InitiateShutdown (int);
115 static void Shutdown (int);
116 static void RefreshAddr (int);
117 static void ParseOption (const char* option, const char* parms);
118 static void ReadConfigFile (const char* fileName);
119 static void SetupPortRedirect (const char* parms);
120 static void SetupProtoRedirect(const char* parms);
121 static void SetupAddressRedirect (const char* parms);
122 static void StrToAddr (const char* str, struct in_addr* addr);
123 static u_short StrToPort (const char* str, const char* proto);
124 static int StrToPortRange (const char* str, const char* proto, port_range *portRange);
125 static int StrToProto (const char* str);
126 static int StrToAddrAndPortRange (char* str, struct in_addr* addr, char* proto, port_range *portRange);
127 static void ParseArgs (int argc, char** argv);
128 static void SetupPunchFW(const char *strValue);
129 static void SetupSkinnyPort(const char *strValue);
130 static void NewInstance(const char *name);
131 static void DoGlobal (int fd);
132 static int CheckIpfwRulenum(unsigned int rnum);
139 static int background;
141 static int logFacility;
143 static int dynamicMode;
145 static int logIpfwDenied;
146 static const char* pidName;
147 static int routeSock;
148 static int globalPort;
149 static int divertGlobal;
150 static int exitDelay;
153 int main (int argc, char** argv)
155 struct sockaddr_in addr;
160 * Initialize packet aliasing software.
161 * Done already here to be able to alter option bits
162 * during command line and configuration file processing.
164 NewInstance("default");
173 logFacility = LOG_DAEMON;
180 exitDelay = EXIT_DELAY;
182 ParseArgs (argc, argv);
184 * Log ipfw(8) denied packets by default in verbose mode.
186 if (logIpfwDenied == -1)
187 logIpfwDenied = verbose;
189 * Open syslog channel.
191 openlog ("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0),
194 LIST_FOREACH(mip, &root, list) {
197 * If not doing the transparent proxying only,
198 * check that valid aliasing address has been given.
200 if (mip->aliasAddr.s_addr == INADDR_NONE && mip->ifName == NULL &&
201 !(LibAliasSetMode(mla, 0,0) & PKT_ALIAS_PROXY_ONLY))
202 errx (1, "instance %s: aliasing address not given", mip->name);
204 if (mip->aliasAddr.s_addr != INADDR_NONE && mip->ifName != NULL)
205 errx (1, "both alias address and interface "
206 "name are not allowed");
208 * Check that valid port number is known.
210 if (mip->inPort != 0 || mip->outPort != 0)
211 if (mip->inPort == 0 || mip->outPort == 0)
212 errx (1, "both input and output ports are required");
214 if (mip->inPort == 0 && mip->outPort == 0 && mip->inOutPort == 0)
215 ParseOption ("port", DEFAULT_SERVICE);
218 * Check if ignored packets should be dropped.
220 mip->dropIgnoredIncoming = LibAliasSetMode (mla, 0, 0);
221 mip->dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING;
223 * Create divert sockets. Use only one socket if -p was specified
224 * on command line. Otherwise, create separate sockets for
225 * outgoing and incoming connections.
227 if (mip->inOutPort) {
229 mip->divertInOut = socket(PF_DIVERT, SOCK_RAW, 0);
230 if (mip->divertInOut == -1)
231 Quit ("Unable to create divert socket.");
232 if (mip->divertInOut > fdMax)
233 fdMax = mip->divertInOut;
241 addr.sin_family = AF_INET;
242 addr.sin_addr.s_addr = INADDR_ANY;
243 addr.sin_port = mip->inOutPort;
245 if (bind (mip->divertInOut,
246 (struct sockaddr*) &addr,
248 Quit ("Unable to bind divert socket.");
252 mip->divertIn = socket(PF_DIVERT, SOCK_RAW, 0);
253 if (mip->divertIn == -1)
254 Quit ("Unable to create incoming divert socket.");
255 if (mip->divertIn > fdMax)
256 fdMax = mip->divertIn;
259 mip->divertOut = socket(PF_DIVERT, SOCK_RAW, 0);
260 if (mip->divertOut == -1)
261 Quit ("Unable to create outgoing divert socket.");
262 if (mip->divertOut > fdMax)
263 fdMax = mip->divertOut;
265 mip->divertInOut = -1;
268 * Bind divert sockets.
271 addr.sin_family = AF_INET;
272 addr.sin_addr.s_addr = INADDR_ANY;
273 addr.sin_port = mip->inPort;
275 if (bind (mip->divertIn,
276 (struct sockaddr*) &addr,
278 Quit ("Unable to bind incoming divert socket.");
280 addr.sin_family = AF_INET;
281 addr.sin_addr.s_addr = INADDR_ANY;
282 addr.sin_port = mip->outPort;
284 if (bind (mip->divertOut,
285 (struct sockaddr*) &addr,
287 Quit ("Unable to bind outgoing divert socket.");
290 * Create routing socket if interface name specified and in dynamic mode.
296 routeSock = socket (PF_ROUTE, SOCK_RAW, 0);
298 Quit ("Unable to create routing info socket.");
299 if (routeSock > fdMax)
302 mip->assignAliasAddr = 1;
306 rval = SetAliasAddressFromIfName (mip->ifName);
307 if (background == 0 || dynamicMode == 0)
311 } while (rval == EAGAIN);
320 divertGlobal = socket(PF_DIVERT, SOCK_RAW, 0);
321 if (divertGlobal == -1)
322 Quit ("Unable to create divert socket.");
323 if (divertGlobal > fdMax)
324 fdMax = divertGlobal;
330 addr.sin_family = AF_INET;
331 addr.sin_addr.s_addr = INADDR_ANY;
332 addr.sin_port = globalPort;
334 if (bind (divertGlobal,
335 (struct sockaddr*) &addr,
337 Quit ("Unable to bind global divert socket.");
340 * Create socket for sending ICMP messages.
342 icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
344 Quit ("Unable to create ICMP socket.");
347 * And disable reads for the socket, otherwise it slowly fills
348 * up with received icmps which we do not use.
350 shutdown(icmpSock, SHUT_RD);
353 * Become a daemon unless verbose mode was requested.
358 * Catch signals to manage shutdown and
359 * refresh of interface address.
361 siginterrupt(SIGTERM, 1);
362 siginterrupt(SIGHUP, 1);
364 signal(SIGTERM, InitiateShutdown);
366 signal(SIGTERM, Shutdown);
367 signal (SIGHUP, RefreshAddr);
369 * Set alias address if it has been given.
371 mip = LIST_FIRST(&root); /* XXX: simon */
372 LIST_FOREACH(mip, &root, list) {
374 if (mip->aliasAddr.s_addr != INADDR_NONE)
375 LibAliasSetAddress (mla, mip->aliasAddr);
379 mip = LIST_FIRST(&root); /* XXX: simon */
381 if (mip->divertInOut != -1 && !mip->ifName && ninstance == 1) {
383 * When using only one socket, just call
384 * DoAliasing repeatedly to process packets.
386 DoAliasing (mip->divertInOut, DONT_KNOW);
390 * Build read mask from socket descriptors to select.
394 * Check if new packets are available.
396 LIST_FOREACH(mip, &root, list) {
397 if (mip->divertIn != -1)
398 FD_SET (mip->divertIn, &readMask);
400 if (mip->divertOut != -1)
401 FD_SET (mip->divertOut, &readMask);
403 if (mip->divertInOut != -1)
404 FD_SET (mip->divertInOut, &readMask);
407 * Routing info is processed always.
410 FD_SET (routeSock, &readMask);
412 if (divertGlobal != -1)
413 FD_SET (divertGlobal, &readMask);
415 if (select (fdMax + 1,
424 Quit ("Select failed.");
427 if (divertGlobal != -1)
428 if (FD_ISSET (divertGlobal, &readMask))
429 DoGlobal (divertGlobal);
430 LIST_FOREACH(mip, &root, list) {
432 if (mip->divertIn != -1)
433 if (FD_ISSET (mip->divertIn, &readMask))
434 DoAliasing (mip->divertIn, INPUT);
436 if (mip->divertOut != -1)
437 if (FD_ISSET (mip->divertOut, &readMask))
438 DoAliasing (mip->divertOut, OUTPUT);
440 if (mip->divertInOut != -1)
441 if (FD_ISSET (mip->divertInOut, &readMask))
442 DoAliasing (mip->divertInOut, DONT_KNOW);
446 if (FD_ISSET (routeSock, &readMask))
447 HandleRoutingInfo (routeSock);
456 static void DaemonMode(void)
463 pidFile = fopen (pidName, "w");
466 fprintf (pidFile, "%d\n", getpid ());
471 static void ParseArgs (int argc, char** argv)
476 int len; /* bounds checking */
478 for (arg = 1; arg < argc; arg++) {
483 warnx ("invalid option %s", opt);
490 while (arg < argc - 1) {
492 if (argv[arg + 1][0] == '-')
496 strncat (parmBuf, " ", sizeof(parmBuf) - (len + 1));
497 len += strlen(parmBuf + len);
501 strncat (parmBuf, argv[arg], sizeof(parmBuf) - (len + 1));
502 len += strlen(parmBuf + len);
506 ParseOption (opt + 1, (len ? parmBuf : NULL));
511 static void DoGlobal (int fd)
515 char buf[IP_MAXPACKET];
516 struct sockaddr_in addr;
523 * Get packet from socket.
525 addrSize = sizeof addr;
526 origBytes = recvfrom (fd,
530 (struct sockaddr*) &addr,
533 if (origBytes == -1) {
536 Warn ("read from divert socket failed");
542 if (mip->assignAliasAddr) {
543 if (SetAliasAddressFromIfName (mip->ifName) != 0)
545 mip->assignAliasAddr = 0;
549 * This is an IP packet.
551 ip = (struct ip*) buf;
555 * Print packet direction and protocol type.
573 printf ("[%d] ", ip->ip_p);
582 LIST_FOREACH(mip, &root, list) {
584 if (LibAliasOutTry (mla, buf, IP_MAXPACKET, 0) != PKT_ALIAS_IGNORED)
588 * Length might have changed during aliasing.
590 bytes = ntohs (ip->ip_len);
592 * Update alias overhead size for outgoing packets.
594 if (mip != NULL && bytes - origBytes > mip->aliasOverhead)
595 mip->aliasOverhead = bytes - origBytes;
600 * Print addresses after aliasing.
602 printf (" aliased to\n");
609 * Put packet back for processing.
615 (struct sockaddr*) &addr,
618 if (wrote != bytes) {
620 if (errno == EMSGSIZE && mip != NULL) {
622 if (mip->ifMTU != -1)
623 SendNeedFragIcmp (icmpSock,
625 mip->ifMTU - mip->aliasOverhead);
627 else if (errno == EACCES && logIpfwDenied) {
629 sprintf (msgBuf, "failed to write packet back");
636 static void DoAliasing (int fd, int direction)
640 char buf[IP_MAXPACKET];
641 struct sockaddr_in addr;
649 if (mip->assignAliasAddr) {
651 rval = SetAliasAddressFromIfName (mip->ifName);
652 if (background == 0 || dynamicMode == 0)
656 } while (rval == EAGAIN);
659 mip->assignAliasAddr = 0;
662 * Get packet from socket.
664 addrSize = sizeof addr;
665 origBytes = recvfrom (fd,
669 (struct sockaddr*) &addr,
672 if (origBytes == -1) {
675 Warn ("read from divert socket failed");
680 * This is an IP packet.
682 ip = (struct ip*) buf;
683 if (direction == DONT_KNOW) {
684 if (addr.sin_addr.s_addr == INADDR_ANY)
692 * Print packet direction and protocol type.
694 printf (direction == OUTPUT ? "Out " : "In ");
696 printf ("{%s}", mip->name);
712 printf ("[%d] ", ip->ip_p);
721 if (direction == OUTPUT) {
723 * Outgoing packets. Do aliasing.
725 LibAliasOut (mla, buf, IP_MAXPACKET);
732 status = LibAliasIn (mla, buf, IP_MAXPACKET);
733 if (status == PKT_ALIAS_IGNORED &&
734 mip->dropIgnoredIncoming) {
737 printf (" dropped.\n");
740 SyslogPacket (ip, LOG_WARNING, "denied");
746 * Length might have changed during aliasing.
748 bytes = ntohs (ip->ip_len);
750 * Update alias overhead size for outgoing packets.
752 if (direction == OUTPUT &&
753 bytes - origBytes > mip->aliasOverhead)
754 mip->aliasOverhead = bytes - origBytes;
759 * Print addresses after aliasing.
761 printf (" aliased to\n");
768 * Put packet back for processing.
774 (struct sockaddr*) &addr,
777 if (wrote != bytes) {
779 if (errno == EMSGSIZE) {
781 if (direction == OUTPUT &&
783 SendNeedFragIcmp (icmpSock,
785 mip->ifMTU - mip->aliasOverhead);
787 else if (errno == EACCES && logIpfwDenied) {
789 sprintf (msgBuf, "failed to write packet back");
795 static void HandleRoutingInfo (int fd)
798 struct if_msghdr ifMsg;
800 * Get packet from socket.
802 bytes = read (fd, &ifMsg, sizeof ifMsg);
805 Warn ("read from routing socket failed");
809 if (ifMsg.ifm_version != RTM_VERSION) {
811 Warn ("unexpected packet read from routing socket");
816 printf ("Routing message %#x received.\n", ifMsg.ifm_type);
818 if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO)) {
819 LIST_FOREACH(mip, &root, list) {
821 if (ifMsg.ifm_index == mip->ifIndex) {
823 printf("Interface address/MTU has probably changed.\n");
824 mip->assignAliasAddr = 1;
830 static void PrintPacket (struct ip* ip)
832 printf ("%s", FormatPacket (ip));
835 static void SyslogPacket (struct ip* ip, int priority, const char *label)
837 syslog (priority, "%s %s", label, FormatPacket (ip));
840 static char* FormatPacket (struct ip* ip)
842 static char buf[256];
843 struct tcphdr* tcphdr;
844 struct udphdr* udphdr;
845 struct icmp* icmphdr;
849 strcpy (src, inet_ntoa (ip->ip_src));
850 strcpy (dst, inet_ntoa (ip->ip_dst));
854 tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2));
855 sprintf (buf, "[TCP] %s:%d -> %s:%d",
857 ntohs (tcphdr->th_sport),
859 ntohs (tcphdr->th_dport));
863 udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2));
864 sprintf (buf, "[UDP] %s:%d -> %s:%d",
866 ntohs (udphdr->uh_sport),
868 ntohs (udphdr->uh_dport));
872 icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2));
873 sprintf (buf, "[ICMP] %s -> %s %u(%u)",
881 sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst);
889 SetAliasAddressFromIfName(const char *ifn)
893 char *buf, *lim, *next;
894 struct if_msghdr *ifm;
895 struct ifa_msghdr *ifam;
896 struct sockaddr_dl *sdl;
897 struct sockaddr_in *sin;
902 mib[3] = AF_INET; /* Only IP addresses please */
903 mib[4] = NET_RT_IFLIST;
904 mib[5] = 0; /* ifIndex??? */
906 * Get interface data.
908 if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
909 err(1, "iflist-sysctl-estimate");
910 if ((buf = malloc(needed)) == NULL)
911 errx(1, "malloc failed");
912 if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1 && errno != ENOMEM)
913 err(1, "iflist-sysctl-get");
916 * Loop through interfaces until one with
917 * given name is found. This is done to
918 * find correct interface index for routing
919 * message processing.
924 ifm = (struct if_msghdr *)next;
925 next += ifm->ifm_msglen;
926 if (ifm->ifm_version != RTM_VERSION) {
928 warnx("routing message version %d "
929 "not understood", ifm->ifm_version);
932 if (ifm->ifm_type == RTM_IFINFO) {
933 sdl = (struct sockaddr_dl *)(ifm + 1);
934 if (strlen(ifn) == sdl->sdl_nlen &&
935 strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) {
936 mip->ifIndex = ifm->ifm_index;
937 mip->ifMTU = ifm->ifm_data.ifi_mtu;
943 errx(1, "unknown interface name %s", ifn);
945 * Get interface address.
949 ifam = (struct ifa_msghdr *)next;
950 next += ifam->ifam_msglen;
951 if (ifam->ifam_version != RTM_VERSION) {
953 warnx("routing message version %d "
954 "not understood", ifam->ifam_version);
957 if (ifam->ifam_type != RTM_NEWADDR)
959 if (ifam->ifam_addrs & RTA_IFA) {
961 char *cp = (char *)(ifam + 1);
963 for (i = 1; i < RTA_IFA; i <<= 1)
964 if (ifam->ifam_addrs & i)
965 cp += SA_SIZE((struct sockaddr *)cp);
966 if (((struct sockaddr *)cp)->sa_family == AF_INET) {
967 sin = (struct sockaddr_in *)cp;
973 warnx("%s: cannot get interface address", ifn);
978 LibAliasSetAddress(mla, sin->sin_addr);
979 syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes",
980 inet_ntoa(sin->sin_addr), mip->ifMTU);
987 void Quit (const char* msg)
993 void Warn (const char* msg)
996 syslog (LOG_ALERT, "%s (%m)", msg);
1001 static void RefreshAddr (int sig __unused)
1003 LibAliasRefreshModules();
1004 if (mip != NULL && mip->ifName != NULL)
1005 mip->assignAliasAddr = 1;
1008 static void InitiateShutdown (int sig __unused)
1011 * Start timer to allow kernel gracefully
1012 * shutdown existing connections when system
1015 siginterrupt(SIGALRM, 1);
1016 signal (SIGALRM, Shutdown);
1017 ualarm(exitDelay*1000, 1000);
1020 static void Shutdown (int sig __unused)
1026 * Different options recognized by this program.
1067 * Option information structure (used by ParseOption).
1075 const char* parmDescription;
1076 const char* description;
1078 const char* shortName;
1082 * Table of known options.
1085 static struct OptionInfo optionTable[] = {
1088 PKT_ALIAS_UNREGISTERED_ONLY,
1091 "alias only unregistered addresses",
1092 "unregistered_only",
1104 PKT_ALIAS_PROXY_ONLY,
1115 "operate in reverse mode",
1120 PKT_ALIAS_DENY_INCOMING,
1123 "allow incoming connections",
1128 PKT_ALIAS_USE_SOCKETS,
1131 "use sockets to inhibit port conflict",
1136 PKT_ALIAS_SAME_PORTS,
1139 "try to keep original port numbers for connections",
1147 "verbose mode, dump packet information",
1155 "dynamic mode, automatically detect interface address changes",
1162 "number|service_name",
1163 "set port for incoming packets",
1170 "number|service_name",
1171 "set port for outgoing packets",
1178 "number|service_name",
1179 "set port (defaults to natd/divert)",
1186 "number|service_name",
1195 "address to use for aliasing",
1203 "address to use for incoming sessions",
1211 "take aliasing address from interface",
1218 "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
1220 "add transparent proxying / destination NAT",
1227 "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
1228 " [remote_addr[:remote_port_range]]",
1229 "redirect a port (or ports) for incoming traffic",
1236 "proto local_addr [public_addr] [remote_addr]",
1237 "redirect packets of a given proto",
1244 "local_addr[,...] public_addr",
1245 "define mapping between local and public addresses",
1253 "read options from configuration file",
1261 "enable logging of denied incoming packets",
1269 "name of syslog facility to use for logging",
1277 "punch holes in the firewall for incoming FTP/IRC DCC connections",
1285 "set the TCP port for use with the Skinny Station protocol",
1293 "log packets converted by natd, but denied by ipfw",
1301 "store PID in an alternate file",
1308 "name of aliasing engine instance",
1315 "delay in ms before daemon exit after signal",
1320 static void ParseOption (const char* option, const char* parms)
1323 struct OptionInfo* info;
1328 const char* strValue;
1329 struct in_addr addrValue;
1332 const CODE* fac_record = NULL;
1334 * Find option from table.
1336 max = sizeof (optionTable) / sizeof (struct OptionInfo);
1337 for (i = 0, info = optionTable; i < max; i++, info++) {
1339 if (!strcmp (info->name, option))
1342 if (info->shortName)
1343 if (!strcmp (info->shortName, option))
1349 warnx ("unknown option %s", option);
1360 switch (info->parm) {
1365 if (!strcmp (parms, "yes"))
1368 if (!strcmp (parms, "no"))
1371 errx (1, "%s needs yes/no parameter", option);
1376 errx (1, "%s needs service name or "
1377 "port number parameter",
1380 uNumValue = StrToPort (parms, "divert");
1385 numValue = strtol (parms, &end, 10);
1390 errx (1, "%s needs numeric parameter", option);
1396 errx (1, "%s needs parameter", option);
1401 errx (1, "%s does not take parameters", option);
1406 errx (1, "%s needs address/host parameter", option);
1408 StrToAddr (parms, &addrValue);
1412 switch (info->type) {
1413 case LibAliasOption:
1415 aliasValue = yesNoValue ? info->packetAliasOpt : 0;
1416 LibAliasSetMode (mla, aliasValue, info->packetAliasOpt);
1420 verbose = yesNoValue;
1424 dynamicMode = yesNoValue;
1428 mip->inPort = uNumValue;
1432 mip->outPort = uNumValue;
1436 mip->inOutPort = uNumValue;
1440 globalPort = uNumValue;
1444 memcpy (&mip->aliasAddr, &addrValue, sizeof (struct in_addr));
1448 LibAliasSetTarget(mla, addrValue);
1452 SetupPortRedirect (strValue);
1456 SetupProtoRedirect(strValue);
1459 case RedirectAddress:
1460 SetupAddressRedirect (strValue);
1464 LibAliasProxyRule (mla, strValue);
1471 mip->ifName = strdup (strValue);
1475 ReadConfigFile (strValue);
1479 mip->logDropped = yesNoValue;
1484 fac_record = facilitynames;
1485 while (fac_record->c_name != NULL) {
1487 if (!strcmp (fac_record->c_name, strValue)) {
1489 logFacility = fac_record->c_val;
1497 if(fac_record->c_name == NULL)
1498 errx(1, "Unknown log facility name: %s", strValue);
1503 SetupPunchFW(strValue);
1507 SetupSkinnyPort(strValue);
1511 logIpfwDenied = yesNoValue;
1515 pidName = strdup (strValue);
1518 NewInstance(strValue);
1521 if (numValue < 0 || numValue > MAX_EXIT_DELAY)
1522 errx(1, "Incorrect exit delay: %d", numValue);
1523 exitDelay = numValue;
1528 void ReadConfigFile (const char* fileName)
1536 file = fopen (fileName, "r");
1538 err(1, "cannot open config file %s", fileName);
1540 while ((buf = fgetln(file, &len)) != NULL) {
1541 if (buf[len - 1] == '\n')
1542 buf[len - 1] = '\0';
1544 errx(1, "config file format error: "
1545 "last line should end with newline");
1548 * Check for comments, strip off trailing spaces.
1550 if ((ptr = strchr(buf, '#')))
1552 for (ptr = buf; isspace(*ptr); ++ptr)
1556 for (p = strchr(buf, '\0'); isspace(*--p);)
1561 * Extract option name.
1564 while (*ptr && !isspace (*ptr))
1573 * Skip white space between name and parms.
1575 while (*ptr && isspace (*ptr))
1578 ParseOption (option, *ptr ? ptr : NULL);
1584 static void Usage(void)
1588 struct OptionInfo* info;
1590 fprintf (stderr, "Recognized options:\n\n");
1592 max = sizeof (optionTable) / sizeof (struct OptionInfo);
1593 for (i = 0, info = optionTable; i < max; i++, info++) {
1595 fprintf (stderr, "-%-20s %s\n", info->name,
1596 info->parmDescription);
1598 if (info->shortName)
1599 fprintf (stderr, "-%-20s %s\n", info->shortName,
1600 info->parmDescription);
1602 fprintf (stderr, " %s\n\n", info->description);
1608 void SetupPortRedirect (const char* parms)
1613 struct in_addr localAddr;
1614 struct in_addr publicAddr;
1615 struct in_addr remoteAddr;
1616 port_range portRange;
1617 u_short localPort = 0;
1618 u_short publicPort = 0;
1619 u_short remotePort = 0;
1620 u_short numLocalPorts = 0;
1621 u_short numPublicPorts = 0;
1622 u_short numRemotePorts = 0;
1627 struct alias_link *aliaslink = NULL;
1629 buf = strdup (parms);
1631 errx (1, "redirect_port: strdup() failed");
1635 protoName = strtok (buf, " \t");
1637 errx (1, "redirect_port: missing protocol");
1639 proto = StrToProto (protoName);
1641 * Extract local address.
1643 ptr = strtok (NULL, " \t");
1645 errx (1, "redirect_port: missing local address");
1647 separator = strchr(ptr, ',');
1648 if (separator) { /* LSNAT redirection syntax. */
1649 localAddr.s_addr = INADDR_NONE;
1654 if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 )
1655 errx (1, "redirect_port: invalid local port range");
1657 localPort = GETLOPORT(portRange);
1658 numLocalPorts = GETNUMPORTS(portRange);
1663 * Extract public port and optionally address.
1665 ptr = strtok (NULL, " \t");
1667 errx (1, "redirect_port: missing public port");
1669 separator = strchr (ptr, ':');
1671 if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 )
1672 errx (1, "redirect_port: invalid public port range");
1675 publicAddr.s_addr = INADDR_ANY;
1676 if (StrToPortRange (ptr, protoName, &portRange) != 0)
1677 errx (1, "redirect_port: invalid public port range");
1680 publicPort = GETLOPORT(portRange);
1681 numPublicPorts = GETNUMPORTS(portRange);
1684 * Extract remote address and optionally port.
1686 ptr = strtok (NULL, " \t");
1688 separator = strchr (ptr, ':');
1690 if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0)
1691 errx (1, "redirect_port: invalid remote port range");
1693 SETLOPORT(portRange, 0);
1694 SETNUMPORTS(portRange, 1);
1695 StrToAddr (ptr, &remoteAddr);
1699 SETLOPORT(portRange, 0);
1700 SETNUMPORTS(portRange, 1);
1701 remoteAddr.s_addr = INADDR_ANY;
1704 remotePort = GETLOPORT(portRange);
1705 numRemotePorts = GETNUMPORTS(portRange);
1708 * Make sure port ranges match up, then add the redirect ports.
1710 if (numLocalPorts != numPublicPorts)
1711 errx (1, "redirect_port: port ranges must be equal in size");
1713 /* Remote port range is allowed to be '0' which means all ports. */
1714 if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0))
1715 errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
1717 for (i = 0 ; i < numPublicPorts ; ++i) {
1718 /* If remotePort is all ports, set it to 0. */
1719 u_short remotePortCopy = remotePort + i;
1720 if (numRemotePorts == 1 && remotePort == 0)
1723 aliaslink = LibAliasRedirectPort (mla, localAddr,
1724 htons(localPort + i),
1726 htons(remotePortCopy),
1728 htons(publicPort + i),
1733 * Setup LSNAT server pool.
1735 if (serverPool != NULL && aliaslink != NULL) {
1736 ptr = strtok(serverPool, ",");
1737 while (ptr != NULL) {
1738 if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0)
1739 errx(1, "redirect_port: invalid local port range");
1741 localPort = GETLOPORT(portRange);
1742 if (GETNUMPORTS(portRange) != 1)
1743 errx(1, "redirect_port: local port must be single in this context");
1744 LibAliasAddServer(mla, aliaslink, localAddr, htons(localPort));
1745 ptr = strtok(NULL, ",");
1753 SetupProtoRedirect(const char* parms)
1757 struct in_addr localAddr;
1758 struct in_addr publicAddr;
1759 struct in_addr remoteAddr;
1762 struct protoent *protoent;
1764 buf = strdup (parms);
1766 errx (1, "redirect_port: strdup() failed");
1770 protoName = strtok(buf, " \t");
1772 errx(1, "redirect_proto: missing protocol");
1774 protoent = getprotobyname(protoName);
1775 if (protoent == NULL)
1776 errx(1, "redirect_proto: unknown protocol %s", protoName);
1778 proto = protoent->p_proto;
1780 * Extract local address.
1782 ptr = strtok(NULL, " \t");
1784 errx(1, "redirect_proto: missing local address");
1786 StrToAddr(ptr, &localAddr);
1788 * Extract optional public address.
1790 ptr = strtok(NULL, " \t");
1792 StrToAddr(ptr, &publicAddr);
1794 publicAddr.s_addr = INADDR_ANY;
1796 * Extract optional remote address.
1798 ptr = strtok(NULL, " \t");
1800 StrToAddr(ptr, &remoteAddr);
1802 remoteAddr.s_addr = INADDR_ANY;
1804 * Create aliasing link.
1806 (void)LibAliasRedirectProto(mla, localAddr, remoteAddr, publicAddr,
1812 void SetupAddressRedirect (const char* parms)
1817 struct in_addr localAddr;
1818 struct in_addr publicAddr;
1820 struct alias_link *aliaslink;
1822 buf = strdup (parms);
1824 errx (1, "redirect_port: strdup() failed");
1826 * Extract local address.
1828 ptr = strtok (buf, " \t");
1830 errx (1, "redirect_address: missing local address");
1832 separator = strchr(ptr, ',');
1833 if (separator) { /* LSNAT redirection syntax. */
1834 localAddr.s_addr = INADDR_NONE;
1837 StrToAddr (ptr, &localAddr);
1841 * Extract public address.
1843 ptr = strtok (NULL, " \t");
1845 errx (1, "redirect_address: missing public address");
1847 StrToAddr (ptr, &publicAddr);
1848 aliaslink = LibAliasRedirectAddr(mla, localAddr, publicAddr);
1851 * Setup LSNAT server pool.
1853 if (serverPool != NULL && aliaslink != NULL) {
1854 ptr = strtok(serverPool, ",");
1855 while (ptr != NULL) {
1856 StrToAddr(ptr, &localAddr);
1857 LibAliasAddServer(mla, aliaslink, localAddr, htons(~0));
1858 ptr = strtok(NULL, ",");
1865 void StrToAddr (const char* str, struct in_addr* addr)
1869 if (inet_aton (str, addr))
1872 hp = gethostbyname (str);
1874 errx (1, "unknown host %s", str);
1876 memcpy (addr, hp->h_addr, sizeof (struct in_addr));
1879 u_short StrToPort (const char* str, const char* proto)
1885 port = strtol (str, &end, 10);
1887 return htons (port);
1889 sp = getservbyname (str, proto);
1891 errx (1, "%s/%s: unknown service", str, proto);
1896 int StrToPortRange (const char* str, const char* proto, port_range *portRange)
1904 /* First see if this is a service, return corresponding port if so. */
1905 sp = getservbyname (str,proto);
1907 SETLOPORT(*portRange, ntohs(sp->s_port));
1908 SETNUMPORTS(*portRange, 1);
1912 /* Not a service, see if it's a single port or port range. */
1913 sep = strchr (str, '-');
1915 SETLOPORT(*portRange, strtol(str, &end, 10));
1918 SETNUMPORTS(*portRange, 1);
1922 /* Error in port range field. */
1923 errx (1, "%s/%s: unknown service", str, proto);
1926 /* Port range, get the values and sanity check. */
1927 sscanf (str, "%hu-%hu", &loPort, &hiPort);
1928 SETLOPORT(*portRange, loPort);
1929 SETNUMPORTS(*portRange, 0); /* Error by default */
1930 if (loPort <= hiPort)
1931 SETNUMPORTS(*portRange, hiPort - loPort + 1);
1933 if (GETNUMPORTS(*portRange) == 0)
1934 errx (1, "invalid port range %s", str);
1941 StrToProto (const char* str)
1943 if (!strcmp (str, "tcp"))
1946 if (!strcmp (str, "udp"))
1949 errx (1, "unknown protocol %s. Expected tcp or udp", str);
1953 StrToAddrAndPortRange (char* str, struct in_addr* addr, char* proto, port_range *portRange)
1957 ptr = strchr (str, ':');
1959 errx (1, "%s is missing port number", str);
1964 StrToAddr (str, addr);
1965 return StrToPortRange (ptr, proto, portRange);
1969 SetupPunchFW(const char *strValue)
1971 unsigned int base, num;
1973 if (sscanf(strValue, "%u:%u", &base, &num) != 2)
1974 errx(1, "punch_fw: basenumber:count parameter required");
1976 if (CheckIpfwRulenum(base + num - 1) == -1)
1977 errx(1, "punch_fw: basenumber:count parameter should fit "
1978 "the maximum allowed rule numbers");
1980 LibAliasSetFWBase(mla, base, num);
1981 (void)LibAliasSetMode(mla, PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);
1985 SetupSkinnyPort(const char *strValue)
1989 if (sscanf(strValue, "%u", &port) != 1)
1990 errx(1, "skinny_port: port parameter required");
1992 LibAliasSetSkinnyPort(mla, port);
1996 NewInstance(const char *name)
1998 struct instance *ip;
2000 LIST_FOREACH(ip, &root, list) {
2001 if (!strcmp(ip->name, name)) {
2008 ip = calloc(1, sizeof(*ip));
2009 ip->name = strdup(name);
2010 ip->la = LibAliasInit (ip->la);
2011 ip->assignAliasAddr = 0;
2017 ip->aliasAddr.s_addr = INADDR_NONE;
2019 ip->aliasOverhead = 12;
2020 LIST_INSERT_HEAD(&root, ip, list);
2026 CheckIpfwRulenum(unsigned int rnum)
2028 unsigned int default_rule;
2029 size_t len = sizeof(default_rule);
2031 if (sysctlbyname("net.inet.ip.fw.default_rule", &default_rule, &len,
2033 warn("Failed to get the default ipfw rule number, using "
2034 "default historical value 65535. The reason was");
2035 default_rule = 65535;
2037 if (rnum >= default_rule) {