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 <machine/in_cksum.h>
28 #include <netinet/tcp.h>
29 #include <netinet/udp.h>
30 #include <netinet/ip_icmp.h>
32 #include <net/if_dl.h>
33 #include <net/route.h>
34 #include <arpa/inet.h>
53 LIST_ENTRY(instance) list;
62 struct in_addr aliasAddr;
65 int dropIgnoredIncoming;
71 static LIST_HEAD(, instance) root = LIST_HEAD_INITIALIZER(&root);
78 * Default values for input and output
79 * divert socket ports.
82 #define DEFAULT_SERVICE "natd"
85 * Definition of a port range, and macros to deal with values.
86 * FORMAT: HI 16-bits == first port in range, 0 == all ports.
87 * LO 16-bits == number of ports in range
88 * NOTES: - Port values are not stored in network byte order.
91 typedef u_long port_range;
93 #define GETLOPORT(x) ((x) >> 0x10)
94 #define GETNUMPORTS(x) ((x) & 0x0000ffff)
95 #define GETHIPORT(x) (GETLOPORT((x)) + GETNUMPORTS((x)))
97 /* Set y to be the low-port value in port_range variable x. */
98 #define SETLOPORT(x,y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
100 /* Set y to be the number of ports in port_range variable x. */
101 #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y))
104 * Function prototypes.
107 static void DoAliasing (int fd, int direction);
108 static void DaemonMode (void);
109 static void HandleRoutingInfo (int fd);
110 static void Usage (void);
111 static char* FormatPacket (struct ip*);
112 static void PrintPacket (struct ip*);
113 static void SyslogPacket (struct ip*, int priority, const char *label);
114 static void SetAliasAddressFromIfName (const char *ifName);
115 static void InitiateShutdown (int);
116 static void Shutdown (int);
117 static void RefreshAddr (int);
118 static void ParseOption (const char* option, const char* parms);
119 static void ReadConfigFile (const char* fileName);
120 static void SetupPortRedirect (const char* parms);
121 static void SetupProtoRedirect(const char* parms);
122 static void SetupAddressRedirect (const char* parms);
123 static void StrToAddr (const char* str, struct in_addr* addr);
124 static u_short StrToPort (const char* str, const char* proto);
125 static int StrToPortRange (const char* str, const char* proto, port_range *portRange);
126 static int StrToProto (const char* str);
127 static int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange);
128 static void ParseArgs (int argc, char** argv);
129 static void SetupPunchFW(const char *strValue);
130 static void SetupSkinnyPort(const char *strValue);
131 static void NewInstance(const char *name);
132 static void DoGlobal (int fd);
133 static int CheckIpfwRulenum(unsigned int rnum);
140 static int background;
142 static int logFacility;
144 static int dynamicMode;
146 static int logIpfwDenied;
147 static const char* pidName;
148 static int routeSock;
149 static int globalPort;
150 static int divertGlobal;
151 static int exitDelay;
154 int main (int argc, char** argv)
156 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 connnections.
227 if (mip->inOutPort) {
229 mip->divertInOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
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_INET, SOCK_RAW, IPPROTO_DIVERT);
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_INET, SOCK_RAW, IPPROTO_DIVERT);
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;
305 SetAliasAddressFromIfName (mip->ifName);
311 divertGlobal = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
312 if (divertGlobal == -1)
313 Quit ("Unable to create divert socket.");
314 if (divertGlobal > fdMax)
315 fdMax = divertGlobal;
321 addr.sin_family = AF_INET;
322 addr.sin_addr.s_addr = INADDR_ANY;
323 addr.sin_port = globalPort;
325 if (bind (divertGlobal,
326 (struct sockaddr*) &addr,
328 Quit ("Unable to bind global divert socket.");
331 * Create socket for sending ICMP messages.
333 icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
335 Quit ("Unable to create ICMP socket.");
338 * And disable reads for the socket, otherwise it slowly fills
339 * up with received icmps which we do not use.
341 shutdown(icmpSock, SHUT_RD);
344 * Become a daemon unless verbose mode was requested.
349 * Catch signals to manage shutdown and
350 * refresh of interface address.
352 siginterrupt(SIGTERM, 1);
353 siginterrupt(SIGHUP, 1);
355 signal(SIGTERM, InitiateShutdown);
357 signal(SIGTERM, Shutdown);
358 signal (SIGHUP, RefreshAddr);
360 * Set alias address if it has been given.
362 mip = LIST_FIRST(&root); /* XXX: simon */
363 LIST_FOREACH(mip, &root, list) {
365 if (mip->aliasAddr.s_addr != INADDR_NONE)
366 LibAliasSetAddress (mla, mip->aliasAddr);
370 mip = LIST_FIRST(&root); /* XXX: simon */
372 if (mip->divertInOut != -1 && !mip->ifName && ninstance == 1) {
374 * When using only one socket, just call
375 * DoAliasing repeatedly to process packets.
377 DoAliasing (mip->divertInOut, DONT_KNOW);
381 * Build read mask from socket descriptors to select.
385 * Check if new packets are available.
387 LIST_FOREACH(mip, &root, list) {
388 if (mip->divertIn != -1)
389 FD_SET (mip->divertIn, &readMask);
391 if (mip->divertOut != -1)
392 FD_SET (mip->divertOut, &readMask);
394 if (mip->divertInOut != -1)
395 FD_SET (mip->divertInOut, &readMask);
398 * Routing info is processed always.
401 FD_SET (routeSock, &readMask);
403 if (divertGlobal != -1)
404 FD_SET (divertGlobal, &readMask);
406 if (select (fdMax + 1,
415 Quit ("Select failed.");
418 if (divertGlobal != -1)
419 if (FD_ISSET (divertGlobal, &readMask))
420 DoGlobal (divertGlobal);
421 LIST_FOREACH(mip, &root, list) {
423 if (mip->divertIn != -1)
424 if (FD_ISSET (mip->divertIn, &readMask))
425 DoAliasing (mip->divertIn, INPUT);
427 if (mip->divertOut != -1)
428 if (FD_ISSET (mip->divertOut, &readMask))
429 DoAliasing (mip->divertOut, OUTPUT);
431 if (mip->divertInOut != -1)
432 if (FD_ISSET (mip->divertInOut, &readMask))
433 DoAliasing (mip->divertInOut, DONT_KNOW);
437 if (FD_ISSET (routeSock, &readMask))
438 HandleRoutingInfo (routeSock);
447 static void DaemonMode ()
454 pidFile = fopen (pidName, "w");
457 fprintf (pidFile, "%d\n", getpid ());
462 static void ParseArgs (int argc, char** argv)
467 int len; /* bounds checking */
469 for (arg = 1; arg < argc; arg++) {
474 warnx ("invalid option %s", opt);
481 while (arg < argc - 1) {
483 if (argv[arg + 1][0] == '-')
487 strncat (parmBuf, " ", sizeof(parmBuf) - (len + 1));
488 len += strlen(parmBuf + len);
492 strncat (parmBuf, argv[arg], sizeof(parmBuf) - (len + 1));
493 len += strlen(parmBuf + len);
497 ParseOption (opt + 1, (len ? parmBuf : NULL));
502 static void DoGlobal (int fd)
506 char buf[IP_MAXPACKET];
507 struct sockaddr_in addr;
514 * Get packet from socket.
516 addrSize = sizeof addr;
517 origBytes = recvfrom (fd,
521 (struct sockaddr*) &addr,
524 if (origBytes == -1) {
527 Warn ("read from divert socket failed");
533 if (mip->assignAliasAddr) {
534 SetAliasAddressFromIfName (mip->ifName);
535 mip->assignAliasAddr = 0;
539 * This is an IP packet.
541 ip = (struct ip*) buf;
545 * Print packet direction and protocol type.
563 printf ("[%d] ", ip->ip_p);
572 LIST_FOREACH(mip, &root, list) {
574 if (LibAliasOutTry (mla, buf, IP_MAXPACKET, 0) != PKT_ALIAS_IGNORED)
578 * Length might have changed during aliasing.
580 bytes = ntohs (ip->ip_len);
582 * Update alias overhead size for outgoing packets.
584 if (mip != NULL && bytes - origBytes > mip->aliasOverhead)
585 mip->aliasOverhead = bytes - origBytes;
590 * Print addresses after aliasing.
592 printf (" aliased to\n");
599 * Put packet back for processing.
605 (struct sockaddr*) &addr,
608 if (wrote != bytes) {
610 if (errno == EMSGSIZE) {
612 if (mip->ifMTU != -1)
613 SendNeedFragIcmp (icmpSock,
615 mip->ifMTU - mip->aliasOverhead);
617 else if (errno == EACCES && logIpfwDenied) {
619 sprintf (msgBuf, "failed to write packet back");
626 static void DoAliasing (int fd, int direction)
630 char buf[IP_MAXPACKET];
631 struct sockaddr_in addr;
638 if (mip->assignAliasAddr) {
640 SetAliasAddressFromIfName (mip->ifName);
641 mip->assignAliasAddr = 0;
644 * Get packet from socket.
646 addrSize = sizeof addr;
647 origBytes = recvfrom (fd,
651 (struct sockaddr*) &addr,
654 if (origBytes == -1) {
657 Warn ("read from divert socket failed");
662 * This is an IP packet.
664 ip = (struct ip*) buf;
665 if (direction == DONT_KNOW) {
666 if (addr.sin_addr.s_addr == INADDR_ANY)
674 * Print packet direction and protocol type.
676 printf (direction == OUTPUT ? "Out " : "In ");
678 printf ("{%s}", mip->name);
694 printf ("[%d] ", ip->ip_p);
703 if (direction == OUTPUT) {
705 * Outgoing packets. Do aliasing.
707 LibAliasOut (mla, buf, IP_MAXPACKET);
714 status = LibAliasIn (mla, buf, IP_MAXPACKET);
715 if (status == PKT_ALIAS_IGNORED &&
716 mip->dropIgnoredIncoming) {
719 printf (" dropped.\n");
722 SyslogPacket (ip, LOG_WARNING, "denied");
728 * Length might have changed during aliasing.
730 bytes = ntohs (ip->ip_len);
732 * Update alias overhead size for outgoing packets.
734 if (direction == OUTPUT &&
735 bytes - origBytes > mip->aliasOverhead)
736 mip->aliasOverhead = bytes - origBytes;
741 * Print addresses after aliasing.
743 printf (" aliased to\n");
750 * Put packet back for processing.
756 (struct sockaddr*) &addr,
759 if (wrote != bytes) {
761 if (errno == EMSGSIZE) {
763 if (direction == OUTPUT &&
765 SendNeedFragIcmp (icmpSock,
767 mip->ifMTU - mip->aliasOverhead);
769 else if (errno == EACCES && logIpfwDenied) {
771 sprintf (msgBuf, "failed to write packet back");
777 static void HandleRoutingInfo (int fd)
780 struct if_msghdr ifMsg;
782 * Get packet from socket.
784 bytes = read (fd, &ifMsg, sizeof ifMsg);
787 Warn ("read from routing socket failed");
791 if (ifMsg.ifm_version != RTM_VERSION) {
793 Warn ("unexpected packet read from routing socket");
798 printf ("Routing message %#x received.\n", ifMsg.ifm_type);
800 if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO)) {
801 LIST_FOREACH(mip, &root, list) {
803 if (ifMsg.ifm_index == mip->ifIndex) {
805 printf("Interface address/MTU has probably changed.\n");
806 mip->assignAliasAddr = 1;
812 static void PrintPacket (struct ip* ip)
814 printf ("%s", FormatPacket (ip));
817 static void SyslogPacket (struct ip* ip, int priority, const char *label)
819 syslog (priority, "%s %s", label, FormatPacket (ip));
822 static char* FormatPacket (struct ip* ip)
824 static char buf[256];
825 struct tcphdr* tcphdr;
826 struct udphdr* udphdr;
827 struct icmp* icmphdr;
831 strcpy (src, inet_ntoa (ip->ip_src));
832 strcpy (dst, inet_ntoa (ip->ip_dst));
836 tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2));
837 sprintf (buf, "[TCP] %s:%d -> %s:%d",
839 ntohs (tcphdr->th_sport),
841 ntohs (tcphdr->th_dport));
845 udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2));
846 sprintf (buf, "[UDP] %s:%d -> %s:%d",
848 ntohs (udphdr->uh_sport),
850 ntohs (udphdr->uh_dport));
854 icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2));
855 sprintf (buf, "[ICMP] %s -> %s %u(%u)",
863 sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst);
871 SetAliasAddressFromIfName(const char *ifn)
875 char *buf, *lim, *next;
876 struct if_msghdr *ifm;
877 struct ifa_msghdr *ifam;
878 struct sockaddr_dl *sdl;
879 struct sockaddr_in *sin;
884 mib[3] = AF_INET; /* Only IP addresses please */
885 mib[4] = NET_RT_IFLIST;
886 mib[5] = 0; /* ifIndex??? */
888 * Get interface data.
890 if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
891 err(1, "iflist-sysctl-estimate");
892 if ((buf = malloc(needed)) == NULL)
893 errx(1, "malloc failed");
894 if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1 && errno != ENOMEM)
895 err(1, "iflist-sysctl-get");
898 * Loop through interfaces until one with
899 * given name is found. This is done to
900 * find correct interface index for routing
901 * message processing.
906 ifm = (struct if_msghdr *)next;
907 next += ifm->ifm_msglen;
908 if (ifm->ifm_version != RTM_VERSION) {
910 warnx("routing message version %d "
911 "not understood", ifm->ifm_version);
914 if (ifm->ifm_type == RTM_IFINFO) {
915 sdl = (struct sockaddr_dl *)(ifm + 1);
916 if (strlen(ifn) == sdl->sdl_nlen &&
917 strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) {
918 mip->ifIndex = ifm->ifm_index;
919 mip->ifMTU = ifm->ifm_data.ifi_mtu;
925 errx(1, "unknown interface name %s", ifn);
927 * Get interface address.
931 ifam = (struct ifa_msghdr *)next;
932 next += ifam->ifam_msglen;
933 if (ifam->ifam_version != RTM_VERSION) {
935 warnx("routing message version %d "
936 "not understood", ifam->ifam_version);
939 if (ifam->ifam_type != RTM_NEWADDR)
941 if (ifam->ifam_addrs & RTA_IFA) {
943 char *cp = (char *)(ifam + 1);
945 for (i = 1; i < RTA_IFA; i <<= 1)
946 if (ifam->ifam_addrs & i)
947 cp += SA_SIZE((struct sockaddr *)cp);
948 if (((struct sockaddr *)cp)->sa_family == AF_INET) {
949 sin = (struct sockaddr_in *)cp;
955 errx(1, "%s: cannot get interface address", ifn);
957 LibAliasSetAddress(mla, sin->sin_addr);
958 syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes",
959 inet_ntoa(sin->sin_addr), mip->ifMTU);
964 void Quit (const char* msg)
970 void Warn (const char* msg)
973 syslog (LOG_ALERT, "%s (%m)", msg);
978 static void RefreshAddr (int sig __unused)
980 LibAliasRefreshModules();
981 if (mip != NULL && mip->ifName != NULL)
982 mip->assignAliasAddr = 1;
985 static void InitiateShutdown (int sig __unused)
988 * Start timer to allow kernel gracefully
989 * shutdown existing connections when system
992 siginterrupt(SIGALRM, 1);
993 signal (SIGALRM, Shutdown);
994 ualarm(exitDelay*1000, 1000);
997 static void Shutdown (int sig __unused)
1003 * Different options recognized by this program.
1044 * Option information structure (used by ParseOption).
1052 const char* parmDescription;
1053 const char* description;
1055 const char* shortName;
1059 * Table of known options.
1062 static struct OptionInfo optionTable[] = {
1065 PKT_ALIAS_UNREGISTERED_ONLY,
1068 "alias only unregistered addresses",
1069 "unregistered_only",
1081 PKT_ALIAS_PROXY_ONLY,
1092 "operate in reverse mode",
1097 PKT_ALIAS_DENY_INCOMING,
1100 "allow incoming connections",
1105 PKT_ALIAS_USE_SOCKETS,
1108 "use sockets to inhibit port conflict",
1113 PKT_ALIAS_SAME_PORTS,
1116 "try to keep original port numbers for connections",
1124 "verbose mode, dump packet information",
1132 "dynamic mode, automatically detect interface address changes",
1139 "number|service_name",
1140 "set port for incoming packets",
1147 "number|service_name",
1148 "set port for outgoing packets",
1155 "number|service_name",
1156 "set port (defaults to natd/divert)",
1163 "number|service_name",
1172 "address to use for aliasing",
1180 "address to use for incoming sessions",
1188 "take aliasing address from interface",
1195 "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
1197 "add transparent proxying / destination NAT",
1204 "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
1205 " [remote_addr[:remote_port_range]]",
1206 "redirect a port (or ports) for incoming traffic",
1213 "proto local_addr [public_addr] [remote_addr]",
1214 "redirect packets of a given proto",
1221 "local_addr[,...] public_addr",
1222 "define mapping between local and public addresses",
1230 "read options from configuration file",
1238 "enable logging of denied incoming packets",
1246 "name of syslog facility to use for logging",
1254 "punch holes in the firewall for incoming FTP/IRC DCC connections",
1262 "set the TCP port for use with the Skinny Station protocol",
1270 "log packets converted by natd, but denied by ipfw",
1278 "store PID in an alternate file",
1285 "name of aliasing engine instance",
1292 "delay in ms before daemon exit after signal",
1297 static void ParseOption (const char* option, const char* parms)
1300 struct OptionInfo* info;
1305 const char* strValue;
1306 struct in_addr addrValue;
1309 CODE* fac_record = NULL;
1311 * Find option from table.
1313 max = sizeof (optionTable) / sizeof (struct OptionInfo);
1314 for (i = 0, info = optionTable; i < max; i++, info++) {
1316 if (!strcmp (info->name, option))
1319 if (info->shortName)
1320 if (!strcmp (info->shortName, option))
1326 warnx ("unknown option %s", option);
1337 switch (info->parm) {
1342 if (!strcmp (parms, "yes"))
1345 if (!strcmp (parms, "no"))
1348 errx (1, "%s needs yes/no parameter", option);
1353 errx (1, "%s needs service name or "
1354 "port number parameter",
1357 uNumValue = StrToPort (parms, "divert");
1362 numValue = strtol (parms, &end, 10);
1367 errx (1, "%s needs numeric parameter", option);
1373 errx (1, "%s needs parameter", option);
1378 errx (1, "%s does not take parameters", option);
1383 errx (1, "%s needs address/host parameter", option);
1385 StrToAddr (parms, &addrValue);
1389 switch (info->type) {
1390 case LibAliasOption:
1392 aliasValue = yesNoValue ? info->packetAliasOpt : 0;
1393 LibAliasSetMode (mla, aliasValue, info->packetAliasOpt);
1397 verbose = yesNoValue;
1401 dynamicMode = yesNoValue;
1405 mip->inPort = uNumValue;
1409 mip->outPort = uNumValue;
1413 mip->inOutPort = uNumValue;
1417 globalPort = uNumValue;
1421 memcpy (&mip->aliasAddr, &addrValue, sizeof (struct in_addr));
1425 LibAliasSetTarget(mla, addrValue);
1429 SetupPortRedirect (strValue);
1433 SetupProtoRedirect(strValue);
1436 case RedirectAddress:
1437 SetupAddressRedirect (strValue);
1441 LibAliasProxyRule (mla, strValue);
1448 mip->ifName = strdup (strValue);
1452 ReadConfigFile (strValue);
1456 mip->logDropped = yesNoValue;
1461 fac_record = facilitynames;
1462 while (fac_record->c_name != NULL) {
1464 if (!strcmp (fac_record->c_name, strValue)) {
1466 logFacility = fac_record->c_val;
1474 if(fac_record->c_name == NULL)
1475 errx(1, "Unknown log facility name: %s", strValue);
1480 SetupPunchFW(strValue);
1484 SetupSkinnyPort(strValue);
1488 logIpfwDenied = yesNoValue;;
1492 pidName = strdup (strValue);
1495 NewInstance(strValue);
1498 if (numValue < 0 || numValue > MAX_EXIT_DELAY)
1499 errx(1, "Incorrect exit delay: %d", numValue);
1500 exitDelay = numValue;
1505 void ReadConfigFile (const char* fileName)
1513 file = fopen (fileName, "r");
1515 err(1, "cannot open config file %s", fileName);
1517 while ((buf = fgetln(file, &len)) != NULL) {
1518 if (buf[len - 1] == '\n')
1519 buf[len - 1] = '\0';
1521 errx(1, "config file format error: "
1522 "last line should end with newline");
1525 * Check for comments, strip off trailing spaces.
1527 if ((ptr = strchr(buf, '#')))
1529 for (ptr = buf; isspace(*ptr); ++ptr)
1533 for (p = strchr(buf, '\0'); isspace(*--p);)
1538 * Extract option name.
1541 while (*ptr && !isspace (*ptr))
1550 * Skip white space between name and parms.
1552 while (*ptr && isspace (*ptr))
1555 ParseOption (option, *ptr ? ptr : NULL);
1561 static void Usage ()
1565 struct OptionInfo* info;
1567 fprintf (stderr, "Recognized options:\n\n");
1569 max = sizeof (optionTable) / sizeof (struct OptionInfo);
1570 for (i = 0, info = optionTable; i < max; i++, info++) {
1572 fprintf (stderr, "-%-20s %s\n", info->name,
1573 info->parmDescription);
1575 if (info->shortName)
1576 fprintf (stderr, "-%-20s %s\n", info->shortName,
1577 info->parmDescription);
1579 fprintf (stderr, " %s\n\n", info->description);
1585 void SetupPortRedirect (const char* parms)
1590 struct in_addr localAddr;
1591 struct in_addr publicAddr;
1592 struct in_addr remoteAddr;
1593 port_range portRange;
1594 u_short localPort = 0;
1595 u_short publicPort = 0;
1596 u_short remotePort = 0;
1597 u_short numLocalPorts = 0;
1598 u_short numPublicPorts = 0;
1599 u_short numRemotePorts = 0;
1604 struct alias_link *aliaslink = NULL;
1606 buf = strdup (parms);
1608 errx (1, "redirect_port: strdup() failed");
1612 protoName = strtok (buf, " \t");
1614 errx (1, "redirect_port: missing protocol");
1616 proto = StrToProto (protoName);
1618 * Extract local address.
1620 ptr = strtok (NULL, " \t");
1622 errx (1, "redirect_port: missing local address");
1624 separator = strchr(ptr, ',');
1625 if (separator) { /* LSNAT redirection syntax. */
1626 localAddr.s_addr = INADDR_NONE;
1631 if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 )
1632 errx (1, "redirect_port: invalid local port range");
1634 localPort = GETLOPORT(portRange);
1635 numLocalPorts = GETNUMPORTS(portRange);
1640 * Extract public port and optionally address.
1642 ptr = strtok (NULL, " \t");
1644 errx (1, "redirect_port: missing public port");
1646 separator = strchr (ptr, ':');
1648 if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 )
1649 errx (1, "redirect_port: invalid public port range");
1652 publicAddr.s_addr = INADDR_ANY;
1653 if (StrToPortRange (ptr, protoName, &portRange) != 0)
1654 errx (1, "redirect_port: invalid public port range");
1657 publicPort = GETLOPORT(portRange);
1658 numPublicPorts = GETNUMPORTS(portRange);
1661 * Extract remote address and optionally port.
1663 ptr = strtok (NULL, " \t");
1665 separator = strchr (ptr, ':');
1667 if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0)
1668 errx (1, "redirect_port: invalid remote port range");
1670 SETLOPORT(portRange, 0);
1671 SETNUMPORTS(portRange, 1);
1672 StrToAddr (ptr, &remoteAddr);
1676 SETLOPORT(portRange, 0);
1677 SETNUMPORTS(portRange, 1);
1678 remoteAddr.s_addr = INADDR_ANY;
1681 remotePort = GETLOPORT(portRange);
1682 numRemotePorts = GETNUMPORTS(portRange);
1685 * Make sure port ranges match up, then add the redirect ports.
1687 if (numLocalPorts != numPublicPorts)
1688 errx (1, "redirect_port: port ranges must be equal in size");
1690 /* Remote port range is allowed to be '0' which means all ports. */
1691 if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0))
1692 errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
1694 for (i = 0 ; i < numPublicPorts ; ++i) {
1695 /* If remotePort is all ports, set it to 0. */
1696 u_short remotePortCopy = remotePort + i;
1697 if (numRemotePorts == 1 && remotePort == 0)
1700 aliaslink = LibAliasRedirectPort (mla, localAddr,
1701 htons(localPort + i),
1703 htons(remotePortCopy),
1705 htons(publicPort + i),
1710 * Setup LSNAT server pool.
1712 if (serverPool != NULL && aliaslink != NULL) {
1713 ptr = strtok(serverPool, ",");
1714 while (ptr != NULL) {
1715 if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0)
1716 errx(1, "redirect_port: invalid local port range");
1718 localPort = GETLOPORT(portRange);
1719 if (GETNUMPORTS(portRange) != 1)
1720 errx(1, "redirect_port: local port must be single in this context");
1721 LibAliasAddServer(mla, aliaslink, localAddr, htons(localPort));
1722 ptr = strtok(NULL, ",");
1730 SetupProtoRedirect(const char* parms)
1734 struct in_addr localAddr;
1735 struct in_addr publicAddr;
1736 struct in_addr remoteAddr;
1739 struct protoent *protoent;
1741 buf = strdup (parms);
1743 errx (1, "redirect_port: strdup() failed");
1747 protoName = strtok(buf, " \t");
1749 errx(1, "redirect_proto: missing protocol");
1751 protoent = getprotobyname(protoName);
1752 if (protoent == NULL)
1753 errx(1, "redirect_proto: unknown protocol %s", protoName);
1755 proto = protoent->p_proto;
1757 * Extract local address.
1759 ptr = strtok(NULL, " \t");
1761 errx(1, "redirect_proto: missing local address");
1763 StrToAddr(ptr, &localAddr);
1765 * Extract optional public address.
1767 ptr = strtok(NULL, " \t");
1769 StrToAddr(ptr, &publicAddr);
1771 publicAddr.s_addr = INADDR_ANY;
1773 * Extract optional remote address.
1775 ptr = strtok(NULL, " \t");
1777 StrToAddr(ptr, &remoteAddr);
1779 remoteAddr.s_addr = INADDR_ANY;
1781 * Create aliasing link.
1783 (void)LibAliasRedirectProto(mla, localAddr, remoteAddr, publicAddr,
1789 void SetupAddressRedirect (const char* parms)
1794 struct in_addr localAddr;
1795 struct in_addr publicAddr;
1797 struct alias_link *aliaslink;
1799 buf = strdup (parms);
1801 errx (1, "redirect_port: strdup() failed");
1803 * Extract local address.
1805 ptr = strtok (buf, " \t");
1807 errx (1, "redirect_address: missing local address");
1809 separator = strchr(ptr, ',');
1810 if (separator) { /* LSNAT redirection syntax. */
1811 localAddr.s_addr = INADDR_NONE;
1814 StrToAddr (ptr, &localAddr);
1818 * Extract public address.
1820 ptr = strtok (NULL, " \t");
1822 errx (1, "redirect_address: missing public address");
1824 StrToAddr (ptr, &publicAddr);
1825 aliaslink = LibAliasRedirectAddr(mla, localAddr, publicAddr);
1828 * Setup LSNAT server pool.
1830 if (serverPool != NULL && aliaslink != NULL) {
1831 ptr = strtok(serverPool, ",");
1832 while (ptr != NULL) {
1833 StrToAddr(ptr, &localAddr);
1834 LibAliasAddServer(mla, aliaslink, localAddr, htons(~0));
1835 ptr = strtok(NULL, ",");
1842 void StrToAddr (const char* str, struct in_addr* addr)
1846 if (inet_aton (str, addr))
1849 hp = gethostbyname (str);
1851 errx (1, "unknown host %s", str);
1853 memcpy (addr, hp->h_addr, sizeof (struct in_addr));
1856 u_short StrToPort (const char* str, const char* proto)
1862 port = strtol (str, &end, 10);
1864 return htons (port);
1866 sp = getservbyname (str, proto);
1868 errx (1, "%s/%s: unknown service", str, proto);
1873 int StrToPortRange (const char* str, const char* proto, port_range *portRange)
1881 /* First see if this is a service, return corresponding port if so. */
1882 sp = getservbyname (str,proto);
1884 SETLOPORT(*portRange, ntohs(sp->s_port));
1885 SETNUMPORTS(*portRange, 1);
1889 /* Not a service, see if it's a single port or port range. */
1890 sep = strchr (str, '-');
1892 SETLOPORT(*portRange, strtol(str, &end, 10));
1895 SETNUMPORTS(*portRange, 1);
1899 /* Error in port range field. */
1900 errx (1, "%s/%s: unknown service", str, proto);
1903 /* Port range, get the values and sanity check. */
1904 sscanf (str, "%hu-%hu", &loPort, &hiPort);
1905 SETLOPORT(*portRange, loPort);
1906 SETNUMPORTS(*portRange, 0); /* Error by default */
1907 if (loPort <= hiPort)
1908 SETNUMPORTS(*portRange, hiPort - loPort + 1);
1910 if (GETNUMPORTS(*portRange) == 0)
1911 errx (1, "invalid port range %s", str);
1917 int StrToProto (const char* str)
1919 if (!strcmp (str, "tcp"))
1922 if (!strcmp (str, "udp"))
1925 errx (1, "unknown protocol %s. Expected tcp or udp", str);
1928 int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange)
1932 ptr = strchr (str, ':');
1934 errx (1, "%s is missing port number", str);
1939 StrToAddr (str, addr);
1940 return StrToPortRange (ptr, proto, portRange);
1944 SetupPunchFW(const char *strValue)
1946 unsigned int base, num;
1948 if (sscanf(strValue, "%u:%u", &base, &num) != 2)
1949 errx(1, "punch_fw: basenumber:count parameter required");
1951 if (CheckIpfwRulenum(base + num - 1) == -1)
1952 errx(1, "punch_fw: basenumber:count parameter should fit "
1953 "the maximum allowed rule numbers");
1955 LibAliasSetFWBase(mla, base, num);
1956 (void)LibAliasSetMode(mla, PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);
1960 SetupSkinnyPort(const char *strValue)
1964 if (sscanf(strValue, "%u", &port) != 1)
1965 errx(1, "skinny_port: port parameter required");
1967 LibAliasSetSkinnyPort(mla, port);
1971 NewInstance(const char *name)
1973 struct instance *ip;
1975 LIST_FOREACH(ip, &root, list) {
1976 if (!strcmp(ip->name, name)) {
1983 ip = calloc(sizeof *ip, 1);
1984 ip->name = strdup(name);
1985 ip->la = LibAliasInit (ip->la);
1986 ip->assignAliasAddr = 0;
1992 ip->aliasAddr.s_addr = INADDR_NONE;
1994 ip->aliasOverhead = 12;
1995 LIST_INSERT_HEAD(&root, ip, list);
2001 CheckIpfwRulenum(unsigned int rnum)
2003 unsigned int default_rule;
2004 size_t len = sizeof(default_rule);
2006 if (sysctlbyname("net.inet.ip.fw.default_rule", &default_rule, &len,
2008 warn("Failed to get the default ipfw rule number, using "
2009 "default historical value 65535. The reason was");
2010 default_rule = 65535;
2012 if (rnum >= default_rule) {