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);
74 static struct instance *mip;
75 static int ninstance = 1;
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 int 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;
161 * Initialize packet aliasing software.
162 * Done already here to be able to alter option bits
163 * during command line and configuration file processing.
165 NewInstance("default");
174 logFacility = LOG_DAEMON;
181 exitDelay = EXIT_DELAY;
183 ParseArgs (argc, argv);
185 * Log ipfw(8) denied packets by default in verbose mode.
187 if (logIpfwDenied == -1)
188 logIpfwDenied = verbose;
190 * Open syslog channel.
192 openlog ("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0),
195 LIST_FOREACH(mip, &root, list) {
198 * If not doing the transparent proxying only,
199 * check that valid aliasing address has been given.
201 if (mip->aliasAddr.s_addr == INADDR_NONE && mip->ifName == NULL &&
202 !(LibAliasSetMode(mla, 0,0) & PKT_ALIAS_PROXY_ONLY))
203 errx (1, "instance %s: aliasing address not given", mip->name);
205 if (mip->aliasAddr.s_addr != INADDR_NONE && mip->ifName != NULL)
206 errx (1, "both alias address and interface "
207 "name are not allowed");
209 * Check that valid port number is known.
211 if (mip->inPort != 0 || mip->outPort != 0)
212 if (mip->inPort == 0 || mip->outPort == 0)
213 errx (1, "both input and output ports are required");
215 if (mip->inPort == 0 && mip->outPort == 0 && mip->inOutPort == 0)
216 ParseOption ("port", DEFAULT_SERVICE);
219 * Check if ignored packets should be dropped.
221 mip->dropIgnoredIncoming = LibAliasSetMode (mla, 0, 0);
222 mip->dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING;
224 * Create divert sockets. Use only one socket if -p was specified
225 * on command line. Otherwise, create separate sockets for
226 * outgoing and incoming connections.
228 if (mip->inOutPort) {
230 mip->divertInOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
231 if (mip->divertInOut == -1)
232 Quit ("Unable to create divert socket.");
233 if (mip->divertInOut > fdMax)
234 fdMax = mip->divertInOut;
242 addr.sin_family = AF_INET;
243 addr.sin_addr.s_addr = INADDR_ANY;
244 addr.sin_port = mip->inOutPort;
246 if (bind (mip->divertInOut,
247 (struct sockaddr*) &addr,
249 Quit ("Unable to bind divert socket.");
253 mip->divertIn = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
254 if (mip->divertIn == -1)
255 Quit ("Unable to create incoming divert socket.");
256 if (mip->divertIn > fdMax)
257 fdMax = mip->divertIn;
260 mip->divertOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
261 if (mip->divertOut == -1)
262 Quit ("Unable to create outgoing divert socket.");
263 if (mip->divertOut > fdMax)
264 fdMax = mip->divertOut;
266 mip->divertInOut = -1;
269 * Bind divert sockets.
272 addr.sin_family = AF_INET;
273 addr.sin_addr.s_addr = INADDR_ANY;
274 addr.sin_port = mip->inPort;
276 if (bind (mip->divertIn,
277 (struct sockaddr*) &addr,
279 Quit ("Unable to bind incoming divert socket.");
281 addr.sin_family = AF_INET;
282 addr.sin_addr.s_addr = INADDR_ANY;
283 addr.sin_port = mip->outPort;
285 if (bind (mip->divertOut,
286 (struct sockaddr*) &addr,
288 Quit ("Unable to bind outgoing divert socket.");
291 * Create routing socket if interface name specified and in dynamic mode.
297 routeSock = socket (PF_ROUTE, SOCK_RAW, 0);
299 Quit ("Unable to create routing info socket.");
300 if (routeSock > fdMax)
303 mip->assignAliasAddr = 1;
307 rval = SetAliasAddressFromIfName (mip->ifName);
308 if (background == 0 || dynamicMode == 0)
312 } while (rval == EAGAIN);
321 divertGlobal = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
322 if (divertGlobal == -1)
323 Quit ("Unable to create divert socket.");
324 if (divertGlobal > fdMax)
325 fdMax = divertGlobal;
331 addr.sin_family = AF_INET;
332 addr.sin_addr.s_addr = INADDR_ANY;
333 addr.sin_port = globalPort;
335 if (bind (divertGlobal,
336 (struct sockaddr*) &addr,
338 Quit ("Unable to bind global divert socket.");
341 * Create socket for sending ICMP messages.
343 icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
345 Quit ("Unable to create ICMP socket.");
348 * And disable reads for the socket, otherwise it slowly fills
349 * up with received icmps which we do not use.
351 shutdown(icmpSock, SHUT_RD);
354 * Become a daemon unless verbose mode was requested.
359 * Catch signals to manage shutdown and
360 * refresh of interface address.
362 siginterrupt(SIGTERM, 1);
363 siginterrupt(SIGHUP, 1);
365 signal(SIGTERM, InitiateShutdown);
367 signal(SIGTERM, Shutdown);
368 signal (SIGHUP, RefreshAddr);
370 * Set alias address if it has been given.
372 mip = LIST_FIRST(&root); /* XXX: simon */
373 LIST_FOREACH(mip, &root, list) {
375 if (mip->aliasAddr.s_addr != INADDR_NONE)
376 LibAliasSetAddress (mla, mip->aliasAddr);
380 mip = LIST_FIRST(&root); /* XXX: simon */
382 if (mip->divertInOut != -1 && !mip->ifName && ninstance == 1) {
384 * When using only one socket, just call
385 * DoAliasing repeatedly to process packets.
387 DoAliasing (mip->divertInOut, DONT_KNOW);
391 * Build read mask from socket descriptors to select.
395 * Check if new packets are available.
397 LIST_FOREACH(mip, &root, list) {
398 if (mip->divertIn != -1)
399 FD_SET (mip->divertIn, &readMask);
401 if (mip->divertOut != -1)
402 FD_SET (mip->divertOut, &readMask);
404 if (mip->divertInOut != -1)
405 FD_SET (mip->divertInOut, &readMask);
408 * Routing info is processed always.
411 FD_SET (routeSock, &readMask);
413 if (divertGlobal != -1)
414 FD_SET (divertGlobal, &readMask);
416 if (select (fdMax + 1,
425 Quit ("Select failed.");
428 if (divertGlobal != -1)
429 if (FD_ISSET (divertGlobal, &readMask))
430 DoGlobal (divertGlobal);
431 LIST_FOREACH(mip, &root, list) {
433 if (mip->divertIn != -1)
434 if (FD_ISSET (mip->divertIn, &readMask))
435 DoAliasing (mip->divertIn, INPUT);
437 if (mip->divertOut != -1)
438 if (FD_ISSET (mip->divertOut, &readMask))
439 DoAliasing (mip->divertOut, OUTPUT);
441 if (mip->divertInOut != -1)
442 if (FD_ISSET (mip->divertInOut, &readMask))
443 DoAliasing (mip->divertInOut, DONT_KNOW);
447 if (FD_ISSET (routeSock, &readMask))
448 HandleRoutingInfo (routeSock);
457 static void DaemonMode(void)
464 pidFile = fopen (pidName, "w");
467 fprintf (pidFile, "%d\n", getpid ());
472 static void ParseArgs (int argc, char** argv)
477 int len; /* bounds checking */
479 for (arg = 1; arg < argc; arg++) {
484 warnx ("invalid option %s", opt);
491 while (arg < argc - 1) {
493 if (argv[arg + 1][0] == '-')
497 strncat (parmBuf, " ", sizeof(parmBuf) - (len + 1));
498 len += strlen(parmBuf + len);
502 strncat (parmBuf, argv[arg], sizeof(parmBuf) - (len + 1));
503 len += strlen(parmBuf + len);
507 ParseOption (opt + 1, (len ? parmBuf : NULL));
512 static void DoGlobal (int fd)
516 char buf[IP_MAXPACKET];
517 struct sockaddr_in addr;
524 * Get packet from socket.
526 addrSize = sizeof addr;
527 origBytes = recvfrom (fd,
531 (struct sockaddr*) &addr,
534 if (origBytes == -1) {
537 Warn ("read from divert socket failed");
543 if (mip->assignAliasAddr) {
544 if (SetAliasAddressFromIfName (mip->ifName) != 0)
546 mip->assignAliasAddr = 0;
550 * This is an IP packet.
552 ip = (struct ip*) buf;
556 * Print packet direction and protocol type.
574 printf ("[%d] ", ip->ip_p);
583 LIST_FOREACH(mip, &root, list) {
585 if (LibAliasOutTry (mla, buf, IP_MAXPACKET, 0) != PKT_ALIAS_IGNORED)
589 * Length might have changed during aliasing.
591 bytes = ntohs (ip->ip_len);
593 * Update alias overhead size for outgoing packets.
595 if (mip != NULL && bytes - origBytes > mip->aliasOverhead)
596 mip->aliasOverhead = bytes - origBytes;
601 * Print addresses after aliasing.
603 printf (" aliased to\n");
610 * Put packet back for processing.
616 (struct sockaddr*) &addr,
619 if (wrote != bytes) {
621 if (errno == EMSGSIZE) {
623 if (mip->ifMTU != -1)
624 SendNeedFragIcmp (icmpSock,
626 mip->ifMTU - mip->aliasOverhead);
628 else if (errno == EACCES && logIpfwDenied) {
630 sprintf (msgBuf, "failed to write packet back");
637 static void DoAliasing (int fd, int direction)
641 char buf[IP_MAXPACKET];
642 struct sockaddr_in addr;
650 if (mip->assignAliasAddr) {
652 rval = SetAliasAddressFromIfName (mip->ifName);
653 if (background == 0 || dynamicMode == 0)
657 } while (rval == EAGAIN);
660 mip->assignAliasAddr = 0;
663 * Get packet from socket.
665 addrSize = sizeof addr;
666 origBytes = recvfrom (fd,
670 (struct sockaddr*) &addr,
673 if (origBytes == -1) {
676 Warn ("read from divert socket failed");
681 * This is an IP packet.
683 ip = (struct ip*) buf;
684 if (direction == DONT_KNOW) {
685 if (addr.sin_addr.s_addr == INADDR_ANY)
693 * Print packet direction and protocol type.
695 printf (direction == OUTPUT ? "Out " : "In ");
697 printf ("{%s}", mip->name);
713 printf ("[%d] ", ip->ip_p);
722 if (direction == OUTPUT) {
724 * Outgoing packets. Do aliasing.
726 LibAliasOut (mla, buf, IP_MAXPACKET);
733 status = LibAliasIn (mla, buf, IP_MAXPACKET);
734 if (status == PKT_ALIAS_IGNORED &&
735 mip->dropIgnoredIncoming) {
738 printf (" dropped.\n");
741 SyslogPacket (ip, LOG_WARNING, "denied");
747 * Length might have changed during aliasing.
749 bytes = ntohs (ip->ip_len);
751 * Update alias overhead size for outgoing packets.
753 if (direction == OUTPUT &&
754 bytes - origBytes > mip->aliasOverhead)
755 mip->aliasOverhead = bytes - origBytes;
760 * Print addresses after aliasing.
762 printf (" aliased to\n");
769 * Put packet back for processing.
775 (struct sockaddr*) &addr,
778 if (wrote != bytes) {
780 if (errno == EMSGSIZE) {
782 if (direction == OUTPUT &&
784 SendNeedFragIcmp (icmpSock,
786 mip->ifMTU - mip->aliasOverhead);
788 else if (errno == EACCES && logIpfwDenied) {
790 sprintf (msgBuf, "failed to write packet back");
796 static void HandleRoutingInfo (int fd)
799 struct if_msghdr ifMsg;
801 * Get packet from socket.
803 bytes = read (fd, &ifMsg, sizeof ifMsg);
806 Warn ("read from routing socket failed");
810 if (ifMsg.ifm_version != RTM_VERSION) {
812 Warn ("unexpected packet read from routing socket");
817 printf ("Routing message %#x received.\n", ifMsg.ifm_type);
819 if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO)) {
820 LIST_FOREACH(mip, &root, list) {
822 if (ifMsg.ifm_index == mip->ifIndex) {
824 printf("Interface address/MTU has probably changed.\n");
825 mip->assignAliasAddr = 1;
831 static void PrintPacket (struct ip* ip)
833 printf ("%s", FormatPacket (ip));
836 static void SyslogPacket (struct ip* ip, int priority, const char *label)
838 syslog (priority, "%s %s", label, FormatPacket (ip));
841 static char* FormatPacket (struct ip* ip)
843 static char buf[256];
844 struct tcphdr* tcphdr;
845 struct udphdr* udphdr;
846 struct icmp* icmphdr;
850 strcpy (src, inet_ntoa (ip->ip_src));
851 strcpy (dst, inet_ntoa (ip->ip_dst));
855 tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2));
856 sprintf (buf, "[TCP] %s:%d -> %s:%d",
858 ntohs (tcphdr->th_sport),
860 ntohs (tcphdr->th_dport));
864 udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2));
865 sprintf (buf, "[UDP] %s:%d -> %s:%d",
867 ntohs (udphdr->uh_sport),
869 ntohs (udphdr->uh_dport));
873 icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2));
874 sprintf (buf, "[ICMP] %s -> %s %u(%u)",
882 sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst);
890 SetAliasAddressFromIfName(const char *ifn)
894 char *buf, *lim, *next;
895 struct if_msghdr *ifm;
896 struct ifa_msghdr *ifam;
897 struct sockaddr_dl *sdl;
898 struct sockaddr_in *sin;
903 mib[3] = AF_INET; /* Only IP addresses please */
904 mib[4] = NET_RT_IFLIST;
905 mib[5] = 0; /* ifIndex??? */
907 * Get interface data.
909 if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
910 err(1, "iflist-sysctl-estimate");
911 if ((buf = malloc(needed)) == NULL)
912 errx(1, "malloc failed");
913 if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1 && errno != ENOMEM)
914 err(1, "iflist-sysctl-get");
917 * Loop through interfaces until one with
918 * given name is found. This is done to
919 * find correct interface index for routing
920 * message processing.
925 ifm = (struct if_msghdr *)next;
926 next += ifm->ifm_msglen;
927 if (ifm->ifm_version != RTM_VERSION) {
929 warnx("routing message version %d "
930 "not understood", ifm->ifm_version);
933 if (ifm->ifm_type == RTM_IFINFO) {
934 sdl = (struct sockaddr_dl *)(ifm + 1);
935 if (strlen(ifn) == sdl->sdl_nlen &&
936 strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) {
937 mip->ifIndex = ifm->ifm_index;
938 mip->ifMTU = ifm->ifm_data.ifi_mtu;
944 errx(1, "unknown interface name %s", ifn);
946 * Get interface address.
950 ifam = (struct ifa_msghdr *)next;
951 next += ifam->ifam_msglen;
952 if (ifam->ifam_version != RTM_VERSION) {
954 warnx("routing message version %d "
955 "not understood", ifam->ifam_version);
958 if (ifam->ifam_type != RTM_NEWADDR)
960 if (ifam->ifam_addrs & RTA_IFA) {
962 char *cp = (char *)(ifam + 1);
964 for (i = 1; i < RTA_IFA; i <<= 1)
965 if (ifam->ifam_addrs & i)
966 cp += SA_SIZE((struct sockaddr *)cp);
967 if (((struct sockaddr *)cp)->sa_family == AF_INET) {
968 sin = (struct sockaddr_in *)cp;
974 warnx("%s: cannot get interface address", ifn);
979 LibAliasSetAddress(mla, sin->sin_addr);
980 syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes",
981 inet_ntoa(sin->sin_addr), mip->ifMTU);
988 void Quit (const char* msg)
994 void Warn (const char* msg)
997 syslog (LOG_ALERT, "%s (%m)", msg);
1002 static void RefreshAddr (int sig __unused)
1004 LibAliasRefreshModules();
1005 if (mip != NULL && mip->ifName != NULL)
1006 mip->assignAliasAddr = 1;
1009 static void InitiateShutdown (int sig __unused)
1012 * Start timer to allow kernel gracefully
1013 * shutdown existing connections when system
1016 siginterrupt(SIGALRM, 1);
1017 signal (SIGALRM, Shutdown);
1018 ualarm(exitDelay*1000, 1000);
1021 static void Shutdown (int sig __unused)
1027 * Different options recognized by this program.
1068 * Option information structure (used by ParseOption).
1076 const char* parmDescription;
1077 const char* description;
1079 const char* shortName;
1083 * Table of known options.
1086 static struct OptionInfo optionTable[] = {
1089 PKT_ALIAS_UNREGISTERED_ONLY,
1092 "alias only unregistered addresses",
1093 "unregistered_only",
1105 PKT_ALIAS_PROXY_ONLY,
1116 "operate in reverse mode",
1121 PKT_ALIAS_DENY_INCOMING,
1124 "allow incoming connections",
1129 PKT_ALIAS_USE_SOCKETS,
1132 "use sockets to inhibit port conflict",
1137 PKT_ALIAS_SAME_PORTS,
1140 "try to keep original port numbers for connections",
1148 "verbose mode, dump packet information",
1156 "dynamic mode, automatically detect interface address changes",
1163 "number|service_name",
1164 "set port for incoming packets",
1171 "number|service_name",
1172 "set port for outgoing packets",
1179 "number|service_name",
1180 "set port (defaults to natd/divert)",
1187 "number|service_name",
1196 "address to use for aliasing",
1204 "address to use for incoming sessions",
1212 "take aliasing address from interface",
1219 "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
1221 "add transparent proxying / destination NAT",
1228 "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
1229 " [remote_addr[:remote_port_range]]",
1230 "redirect a port (or ports) for incoming traffic",
1237 "proto local_addr [public_addr] [remote_addr]",
1238 "redirect packets of a given proto",
1245 "local_addr[,...] public_addr",
1246 "define mapping between local and public addresses",
1254 "read options from configuration file",
1262 "enable logging of denied incoming packets",
1270 "name of syslog facility to use for logging",
1278 "punch holes in the firewall for incoming FTP/IRC DCC connections",
1286 "set the TCP port for use with the Skinny Station protocol",
1294 "log packets converted by natd, but denied by ipfw",
1302 "store PID in an alternate file",
1309 "name of aliasing engine instance",
1316 "delay in ms before daemon exit after signal",
1321 static void ParseOption (const char* option, const char* parms)
1324 struct OptionInfo* info;
1329 const char* strValue;
1330 struct in_addr addrValue;
1333 const CODE* fac_record = NULL;
1335 * Find option from table.
1337 max = sizeof (optionTable) / sizeof (struct OptionInfo);
1338 for (i = 0, info = optionTable; i < max; i++, info++) {
1340 if (!strcmp (info->name, option))
1343 if (info->shortName)
1344 if (!strcmp (info->shortName, option))
1350 warnx ("unknown option %s", option);
1361 switch (info->parm) {
1366 if (!strcmp (parms, "yes"))
1369 if (!strcmp (parms, "no"))
1372 errx (1, "%s needs yes/no parameter", option);
1377 errx (1, "%s needs service name or "
1378 "port number parameter",
1381 uNumValue = StrToPort (parms, "divert");
1386 numValue = strtol (parms, &end, 10);
1391 errx (1, "%s needs numeric parameter", option);
1397 errx (1, "%s needs parameter", option);
1402 errx (1, "%s does not take parameters", option);
1407 errx (1, "%s needs address/host parameter", option);
1409 StrToAddr (parms, &addrValue);
1413 switch (info->type) {
1414 case LibAliasOption:
1416 aliasValue = yesNoValue ? info->packetAliasOpt : 0;
1417 LibAliasSetMode (mla, aliasValue, info->packetAliasOpt);
1421 verbose = yesNoValue;
1425 dynamicMode = yesNoValue;
1429 mip->inPort = uNumValue;
1433 mip->outPort = uNumValue;
1437 mip->inOutPort = uNumValue;
1441 globalPort = uNumValue;
1445 memcpy (&mip->aliasAddr, &addrValue, sizeof (struct in_addr));
1449 LibAliasSetTarget(mla, addrValue);
1453 SetupPortRedirect (strValue);
1457 SetupProtoRedirect(strValue);
1460 case RedirectAddress:
1461 SetupAddressRedirect (strValue);
1465 LibAliasProxyRule (mla, strValue);
1472 mip->ifName = strdup (strValue);
1476 ReadConfigFile (strValue);
1480 mip->logDropped = yesNoValue;
1485 fac_record = facilitynames;
1486 while (fac_record->c_name != NULL) {
1488 if (!strcmp (fac_record->c_name, strValue)) {
1490 logFacility = fac_record->c_val;
1498 if(fac_record->c_name == NULL)
1499 errx(1, "Unknown log facility name: %s", strValue);
1504 SetupPunchFW(strValue);
1508 SetupSkinnyPort(strValue);
1512 logIpfwDenied = yesNoValue;
1516 pidName = strdup (strValue);
1519 NewInstance(strValue);
1522 if (numValue < 0 || numValue > MAX_EXIT_DELAY)
1523 errx(1, "Incorrect exit delay: %d", numValue);
1524 exitDelay = numValue;
1529 void ReadConfigFile (const char* fileName)
1537 file = fopen (fileName, "r");
1539 err(1, "cannot open config file %s", fileName);
1541 while ((buf = fgetln(file, &len)) != NULL) {
1542 if (buf[len - 1] == '\n')
1543 buf[len - 1] = '\0';
1545 errx(1, "config file format error: "
1546 "last line should end with newline");
1549 * Check for comments, strip off trailing spaces.
1551 if ((ptr = strchr(buf, '#')))
1553 for (ptr = buf; isspace(*ptr); ++ptr)
1557 for (p = strchr(buf, '\0'); isspace(*--p);)
1562 * Extract option name.
1565 while (*ptr && !isspace (*ptr))
1574 * Skip white space between name and parms.
1576 while (*ptr && isspace (*ptr))
1579 ParseOption (option, *ptr ? ptr : NULL);
1585 static void Usage(void)
1589 struct OptionInfo* info;
1591 fprintf (stderr, "Recognized options:\n\n");
1593 max = sizeof (optionTable) / sizeof (struct OptionInfo);
1594 for (i = 0, info = optionTable; i < max; i++, info++) {
1596 fprintf (stderr, "-%-20s %s\n", info->name,
1597 info->parmDescription);
1599 if (info->shortName)
1600 fprintf (stderr, "-%-20s %s\n", info->shortName,
1601 info->parmDescription);
1603 fprintf (stderr, " %s\n\n", info->description);
1609 void SetupPortRedirect (const char* parms)
1614 struct in_addr localAddr;
1615 struct in_addr publicAddr;
1616 struct in_addr remoteAddr;
1617 port_range portRange;
1618 u_short localPort = 0;
1619 u_short publicPort = 0;
1620 u_short remotePort = 0;
1621 u_short numLocalPorts = 0;
1622 u_short numPublicPorts = 0;
1623 u_short numRemotePorts = 0;
1628 struct alias_link *aliaslink = NULL;
1630 buf = strdup (parms);
1632 errx (1, "redirect_port: strdup() failed");
1636 protoName = strtok (buf, " \t");
1638 errx (1, "redirect_port: missing protocol");
1640 proto = StrToProto (protoName);
1642 * Extract local address.
1644 ptr = strtok (NULL, " \t");
1646 errx (1, "redirect_port: missing local address");
1648 separator = strchr(ptr, ',');
1649 if (separator) { /* LSNAT redirection syntax. */
1650 localAddr.s_addr = INADDR_NONE;
1655 if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 )
1656 errx (1, "redirect_port: invalid local port range");
1658 localPort = GETLOPORT(portRange);
1659 numLocalPorts = GETNUMPORTS(portRange);
1664 * Extract public port and optionally address.
1666 ptr = strtok (NULL, " \t");
1668 errx (1, "redirect_port: missing public port");
1670 separator = strchr (ptr, ':');
1672 if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 )
1673 errx (1, "redirect_port: invalid public port range");
1676 publicAddr.s_addr = INADDR_ANY;
1677 if (StrToPortRange (ptr, protoName, &portRange) != 0)
1678 errx (1, "redirect_port: invalid public port range");
1681 publicPort = GETLOPORT(portRange);
1682 numPublicPorts = GETNUMPORTS(portRange);
1685 * Extract remote address and optionally port.
1687 ptr = strtok (NULL, " \t");
1689 separator = strchr (ptr, ':');
1691 if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0)
1692 errx (1, "redirect_port: invalid remote port range");
1694 SETLOPORT(portRange, 0);
1695 SETNUMPORTS(portRange, 1);
1696 StrToAddr (ptr, &remoteAddr);
1700 SETLOPORT(portRange, 0);
1701 SETNUMPORTS(portRange, 1);
1702 remoteAddr.s_addr = INADDR_ANY;
1705 remotePort = GETLOPORT(portRange);
1706 numRemotePorts = GETNUMPORTS(portRange);
1709 * Make sure port ranges match up, then add the redirect ports.
1711 if (numLocalPorts != numPublicPorts)
1712 errx (1, "redirect_port: port ranges must be equal in size");
1714 /* Remote port range is allowed to be '0' which means all ports. */
1715 if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0))
1716 errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
1718 for (i = 0 ; i < numPublicPorts ; ++i) {
1719 /* If remotePort is all ports, set it to 0. */
1720 u_short remotePortCopy = remotePort + i;
1721 if (numRemotePorts == 1 && remotePort == 0)
1724 aliaslink = LibAliasRedirectPort (mla, localAddr,
1725 htons(localPort + i),
1727 htons(remotePortCopy),
1729 htons(publicPort + i),
1734 * Setup LSNAT server pool.
1736 if (serverPool != NULL && aliaslink != NULL) {
1737 ptr = strtok(serverPool, ",");
1738 while (ptr != NULL) {
1739 if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0)
1740 errx(1, "redirect_port: invalid local port range");
1742 localPort = GETLOPORT(portRange);
1743 if (GETNUMPORTS(portRange) != 1)
1744 errx(1, "redirect_port: local port must be single in this context");
1745 LibAliasAddServer(mla, aliaslink, localAddr, htons(localPort));
1746 ptr = strtok(NULL, ",");
1754 SetupProtoRedirect(const char* parms)
1758 struct in_addr localAddr;
1759 struct in_addr publicAddr;
1760 struct in_addr remoteAddr;
1763 struct protoent *protoent;
1765 buf = strdup (parms);
1767 errx (1, "redirect_port: strdup() failed");
1771 protoName = strtok(buf, " \t");
1773 errx(1, "redirect_proto: missing protocol");
1775 protoent = getprotobyname(protoName);
1776 if (protoent == NULL)
1777 errx(1, "redirect_proto: unknown protocol %s", protoName);
1779 proto = protoent->p_proto;
1781 * Extract local address.
1783 ptr = strtok(NULL, " \t");
1785 errx(1, "redirect_proto: missing local address");
1787 StrToAddr(ptr, &localAddr);
1789 * Extract optional public address.
1791 ptr = strtok(NULL, " \t");
1793 StrToAddr(ptr, &publicAddr);
1795 publicAddr.s_addr = INADDR_ANY;
1797 * Extract optional remote address.
1799 ptr = strtok(NULL, " \t");
1801 StrToAddr(ptr, &remoteAddr);
1803 remoteAddr.s_addr = INADDR_ANY;
1805 * Create aliasing link.
1807 (void)LibAliasRedirectProto(mla, localAddr, remoteAddr, publicAddr,
1813 void SetupAddressRedirect (const char* parms)
1818 struct in_addr localAddr;
1819 struct in_addr publicAddr;
1821 struct alias_link *aliaslink;
1823 buf = strdup (parms);
1825 errx (1, "redirect_port: strdup() failed");
1827 * Extract local address.
1829 ptr = strtok (buf, " \t");
1831 errx (1, "redirect_address: missing local address");
1833 separator = strchr(ptr, ',');
1834 if (separator) { /* LSNAT redirection syntax. */
1835 localAddr.s_addr = INADDR_NONE;
1838 StrToAddr (ptr, &localAddr);
1842 * Extract public address.
1844 ptr = strtok (NULL, " \t");
1846 errx (1, "redirect_address: missing public address");
1848 StrToAddr (ptr, &publicAddr);
1849 aliaslink = LibAliasRedirectAddr(mla, localAddr, publicAddr);
1852 * Setup LSNAT server pool.
1854 if (serverPool != NULL && aliaslink != NULL) {
1855 ptr = strtok(serverPool, ",");
1856 while (ptr != NULL) {
1857 StrToAddr(ptr, &localAddr);
1858 LibAliasAddServer(mla, aliaslink, localAddr, htons(~0));
1859 ptr = strtok(NULL, ",");
1866 void StrToAddr (const char* str, struct in_addr* addr)
1870 if (inet_aton (str, addr))
1873 hp = gethostbyname (str);
1875 errx (1, "unknown host %s", str);
1877 memcpy (addr, hp->h_addr, sizeof (struct in_addr));
1880 u_short StrToPort (const char* str, const char* proto)
1886 port = strtol (str, &end, 10);
1888 return htons (port);
1890 sp = getservbyname (str, proto);
1892 errx (1, "%s/%s: unknown service", str, proto);
1897 int StrToPortRange (const char* str, const char* proto, port_range *portRange)
1905 /* First see if this is a service, return corresponding port if so. */
1906 sp = getservbyname (str,proto);
1908 SETLOPORT(*portRange, ntohs(sp->s_port));
1909 SETNUMPORTS(*portRange, 1);
1913 /* Not a service, see if it's a single port or port range. */
1914 sep = strchr (str, '-');
1916 SETLOPORT(*portRange, strtol(str, &end, 10));
1919 SETNUMPORTS(*portRange, 1);
1923 /* Error in port range field. */
1924 errx (1, "%s/%s: unknown service", str, proto);
1927 /* Port range, get the values and sanity check. */
1928 sscanf (str, "%hu-%hu", &loPort, &hiPort);
1929 SETLOPORT(*portRange, loPort);
1930 SETNUMPORTS(*portRange, 0); /* Error by default */
1931 if (loPort <= hiPort)
1932 SETNUMPORTS(*portRange, hiPort - loPort + 1);
1934 if (GETNUMPORTS(*portRange) == 0)
1935 errx (1, "invalid port range %s", str);
1941 int 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);
1952 int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange)
1956 ptr = strchr (str, ':');
1958 errx (1, "%s is missing port number", str);
1963 StrToAddr (str, addr);
1964 return StrToPortRange (ptr, proto, portRange);
1968 SetupPunchFW(const char *strValue)
1970 unsigned int base, num;
1972 if (sscanf(strValue, "%u:%u", &base, &num) != 2)
1973 errx(1, "punch_fw: basenumber:count parameter required");
1975 if (CheckIpfwRulenum(base + num - 1) == -1)
1976 errx(1, "punch_fw: basenumber:count parameter should fit "
1977 "the maximum allowed rule numbers");
1979 LibAliasSetFWBase(mla, base, num);
1980 (void)LibAliasSetMode(mla, PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);
1984 SetupSkinnyPort(const char *strValue)
1988 if (sscanf(strValue, "%u", &port) != 1)
1989 errx(1, "skinny_port: port parameter required");
1991 LibAliasSetSkinnyPort(mla, port);
1995 NewInstance(const char *name)
1997 struct instance *ip;
1999 LIST_FOREACH(ip, &root, list) {
2000 if (!strcmp(ip->name, name)) {
2007 ip = calloc(sizeof *ip, 1);
2008 ip->name = strdup(name);
2009 ip->la = LibAliasInit (ip->la);
2010 ip->assignAliasAddr = 0;
2016 ip->aliasAddr.s_addr = INADDR_NONE;
2018 ip->aliasOverhead = 12;
2019 LIST_INSERT_HEAD(&root, ip, list);
2025 CheckIpfwRulenum(unsigned int rnum)
2027 unsigned int default_rule;
2028 size_t len = sizeof(default_rule);
2030 if (sysctlbyname("net.inet.ip.fw.default_rule", &default_rule, &len,
2032 warn("Failed to get the default ipfw rule number, using "
2033 "default historical value 65535. The reason was");
2034 default_rule = 65535;
2036 if (rnum >= default_rule) {