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;
152 int main (int argc, char** argv)
154 struct sockaddr_in addr;
158 * Initialize packet aliasing software.
159 * Done already here to be able to alter option bits
160 * during command line and configuration file processing.
162 NewInstance("default");
171 logFacility = LOG_DAEMON;
179 ParseArgs (argc, argv);
181 * Log ipfw(8) denied packets by default in verbose mode.
183 if (logIpfwDenied == -1)
184 logIpfwDenied = verbose;
186 * Open syslog channel.
188 openlog ("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0),
191 LIST_FOREACH(mip, &root, list) {
194 * If not doing the transparent proxying only,
195 * check that valid aliasing address has been given.
197 if (mip->aliasAddr.s_addr == INADDR_NONE && mip->ifName == NULL &&
198 !(LibAliasSetMode(mla, 0,0) & PKT_ALIAS_PROXY_ONLY))
199 errx (1, "instance %s: aliasing address not given", mip->name);
201 if (mip->aliasAddr.s_addr != INADDR_NONE && mip->ifName != NULL)
202 errx (1, "both alias address and interface "
203 "name are not allowed");
205 * Check that valid port number is known.
207 if (mip->inPort != 0 || mip->outPort != 0)
208 if (mip->inPort == 0 || mip->outPort == 0)
209 errx (1, "both input and output ports are required");
211 if (mip->inPort == 0 && mip->outPort == 0 && mip->inOutPort == 0)
212 ParseOption ("port", DEFAULT_SERVICE);
215 * Check if ignored packets should be dropped.
217 mip->dropIgnoredIncoming = LibAliasSetMode (mla, 0, 0);
218 mip->dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING;
220 * Create divert sockets. Use only one socket if -p was specified
221 * on command line. Otherwise, create separate sockets for
222 * outgoing and incoming connnections.
224 if (mip->inOutPort) {
226 mip->divertInOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
227 if (mip->divertInOut == -1)
228 Quit ("Unable to create divert socket.");
229 if (mip->divertInOut > fdMax)
230 fdMax = mip->divertInOut;
238 addr.sin_family = AF_INET;
239 addr.sin_addr.s_addr = INADDR_ANY;
240 addr.sin_port = mip->inOutPort;
242 if (bind (mip->divertInOut,
243 (struct sockaddr*) &addr,
245 Quit ("Unable to bind divert socket.");
249 mip->divertIn = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
250 if (mip->divertIn == -1)
251 Quit ("Unable to create incoming divert socket.");
252 if (mip->divertIn > fdMax)
253 fdMax = mip->divertIn;
256 mip->divertOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
257 if (mip->divertOut == -1)
258 Quit ("Unable to create outgoing divert socket.");
259 if (mip->divertOut > fdMax)
260 fdMax = mip->divertOut;
262 mip->divertInOut = -1;
265 * Bind divert sockets.
268 addr.sin_family = AF_INET;
269 addr.sin_addr.s_addr = INADDR_ANY;
270 addr.sin_port = mip->inPort;
272 if (bind (mip->divertIn,
273 (struct sockaddr*) &addr,
275 Quit ("Unable to bind incoming divert socket.");
277 addr.sin_family = AF_INET;
278 addr.sin_addr.s_addr = INADDR_ANY;
279 addr.sin_port = mip->outPort;
281 if (bind (mip->divertOut,
282 (struct sockaddr*) &addr,
284 Quit ("Unable to bind outgoing divert socket.");
287 * Create routing socket if interface name specified and in dynamic mode.
293 routeSock = socket (PF_ROUTE, SOCK_RAW, 0);
295 Quit ("Unable to create routing info socket.");
296 if (routeSock > fdMax)
299 mip->assignAliasAddr = 1;
302 SetAliasAddressFromIfName (mip->ifName);
308 divertGlobal = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
309 if (divertGlobal == -1)
310 Quit ("Unable to create divert socket.");
311 if (divertGlobal > fdMax)
312 fdMax = divertGlobal;
318 addr.sin_family = AF_INET;
319 addr.sin_addr.s_addr = INADDR_ANY;
320 addr.sin_port = globalPort;
322 if (bind (divertGlobal,
323 (struct sockaddr*) &addr,
325 Quit ("Unable to bind global divert socket.");
328 * Create socket for sending ICMP messages.
330 icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
332 Quit ("Unable to create ICMP socket.");
335 * And disable reads for the socket, otherwise it slowly fills
336 * up with received icmps which we do not use.
338 shutdown(icmpSock, SHUT_RD);
341 * Become a daemon unless verbose mode was requested.
346 * Catch signals to manage shutdown and
347 * refresh of interface address.
349 siginterrupt(SIGTERM, 1);
350 siginterrupt(SIGHUP, 1);
351 signal (SIGTERM, InitiateShutdown);
352 signal (SIGHUP, RefreshAddr);
354 * Set alias address if it has been given.
356 mip = LIST_FIRST(&root); /* XXX: simon */
357 LIST_FOREACH(mip, &root, list) {
359 if (mip->aliasAddr.s_addr != INADDR_NONE)
360 LibAliasSetAddress (mla, mip->aliasAddr);
364 mip = LIST_FIRST(&root); /* XXX: simon */
366 if (mip->divertInOut != -1 && !mip->ifName && ninstance == 1) {
368 * When using only one socket, just call
369 * DoAliasing repeatedly to process packets.
371 DoAliasing (mip->divertInOut, DONT_KNOW);
375 * Build read mask from socket descriptors to select.
379 * Check if new packets are available.
381 LIST_FOREACH(mip, &root, list) {
382 if (mip->divertIn != -1)
383 FD_SET (mip->divertIn, &readMask);
385 if (mip->divertOut != -1)
386 FD_SET (mip->divertOut, &readMask);
388 if (mip->divertInOut != -1)
389 FD_SET (mip->divertInOut, &readMask);
392 * Routing info is processed always.
395 FD_SET (routeSock, &readMask);
397 if (divertGlobal != -1)
398 FD_SET (divertGlobal, &readMask);
400 if (select (fdMax + 1,
409 Quit ("Select failed.");
412 if (divertGlobal != -1)
413 if (FD_ISSET (divertGlobal, &readMask))
414 DoGlobal (divertGlobal);
415 LIST_FOREACH(mip, &root, list) {
417 if (mip->divertIn != -1)
418 if (FD_ISSET (mip->divertIn, &readMask))
419 DoAliasing (mip->divertIn, INPUT);
421 if (mip->divertOut != -1)
422 if (FD_ISSET (mip->divertOut, &readMask))
423 DoAliasing (mip->divertOut, OUTPUT);
425 if (mip->divertInOut != -1)
426 if (FD_ISSET (mip->divertInOut, &readMask))
427 DoAliasing (mip->divertInOut, DONT_KNOW);
431 if (FD_ISSET (routeSock, &readMask))
432 HandleRoutingInfo (routeSock);
441 static void DaemonMode ()
448 pidFile = fopen (pidName, "w");
451 fprintf (pidFile, "%d\n", getpid ());
456 static void ParseArgs (int argc, char** argv)
461 int len; /* bounds checking */
463 for (arg = 1; arg < argc; arg++) {
468 warnx ("invalid option %s", opt);
475 while (arg < argc - 1) {
477 if (argv[arg + 1][0] == '-')
481 strncat (parmBuf, " ", sizeof(parmBuf) - (len + 1));
482 len += strlen(parmBuf + len);
486 strncat (parmBuf, argv[arg], sizeof(parmBuf) - (len + 1));
487 len += strlen(parmBuf + len);
491 ParseOption (opt + 1, (len ? parmBuf : NULL));
496 static void DoGlobal (int fd)
500 char buf[IP_MAXPACKET];
501 struct sockaddr_in addr;
508 * Get packet from socket.
510 addrSize = sizeof addr;
511 origBytes = recvfrom (fd,
515 (struct sockaddr*) &addr,
518 if (origBytes == -1) {
521 Warn ("read from divert socket failed");
527 if (mip->assignAliasAddr) {
528 SetAliasAddressFromIfName (mip->ifName);
529 mip->assignAliasAddr = 0;
533 * This is an IP packet.
535 ip = (struct ip*) buf;
539 * Print packet direction and protocol type.
557 printf ("[%d] ", ip->ip_p);
566 LIST_FOREACH(mip, &root, list) {
568 if (LibAliasOutTry (mla, buf, IP_MAXPACKET, 0) != PKT_ALIAS_IGNORED)
572 * Length might have changed during aliasing.
574 bytes = ntohs (ip->ip_len);
576 * Update alias overhead size for outgoing packets.
578 if (mip != NULL && bytes - origBytes > mip->aliasOverhead)
579 mip->aliasOverhead = bytes - origBytes;
584 * Print addresses after aliasing.
586 printf (" aliased to\n");
593 * Put packet back for processing.
599 (struct sockaddr*) &addr,
602 if (wrote != bytes) {
604 if (errno == EMSGSIZE) {
606 if (mip->ifMTU != -1)
607 SendNeedFragIcmp (icmpSock,
609 mip->ifMTU - mip->aliasOverhead);
611 else if (errno == EACCES && logIpfwDenied) {
613 sprintf (msgBuf, "failed to write packet back");
620 static void DoAliasing (int fd, int direction)
624 char buf[IP_MAXPACKET];
625 struct sockaddr_in addr;
632 if (mip->assignAliasAddr) {
634 SetAliasAddressFromIfName (mip->ifName);
635 mip->assignAliasAddr = 0;
638 * Get packet from socket.
640 addrSize = sizeof addr;
641 origBytes = recvfrom (fd,
645 (struct sockaddr*) &addr,
648 if (origBytes == -1) {
651 Warn ("read from divert socket failed");
656 * This is an IP packet.
658 ip = (struct ip*) buf;
659 if (direction == DONT_KNOW) {
660 if (addr.sin_addr.s_addr == INADDR_ANY)
668 * Print packet direction and protocol type.
670 printf (direction == OUTPUT ? "Out " : "In ");
672 printf ("{%s}", mip->name);
688 printf ("[%d] ", ip->ip_p);
697 if (direction == OUTPUT) {
699 * Outgoing packets. Do aliasing.
701 LibAliasOut (mla, buf, IP_MAXPACKET);
708 status = LibAliasIn (mla, buf, IP_MAXPACKET);
709 if (status == PKT_ALIAS_IGNORED &&
710 mip->dropIgnoredIncoming) {
713 printf (" dropped.\n");
716 SyslogPacket (ip, LOG_WARNING, "denied");
722 * Length might have changed during aliasing.
724 bytes = ntohs (ip->ip_len);
726 * Update alias overhead size for outgoing packets.
728 if (direction == OUTPUT &&
729 bytes - origBytes > mip->aliasOverhead)
730 mip->aliasOverhead = bytes - origBytes;
735 * Print addresses after aliasing.
737 printf (" aliased to\n");
744 * Put packet back for processing.
750 (struct sockaddr*) &addr,
753 if (wrote != bytes) {
755 if (errno == EMSGSIZE) {
757 if (direction == OUTPUT &&
759 SendNeedFragIcmp (icmpSock,
761 mip->ifMTU - mip->aliasOverhead);
763 else if (errno == EACCES && logIpfwDenied) {
765 sprintf (msgBuf, "failed to write packet back");
771 static void HandleRoutingInfo (int fd)
774 struct if_msghdr ifMsg;
776 * Get packet from socket.
778 bytes = read (fd, &ifMsg, sizeof ifMsg);
781 Warn ("read from routing socket failed");
785 if (ifMsg.ifm_version != RTM_VERSION) {
787 Warn ("unexpected packet read from routing socket");
792 printf ("Routing message %#x received.\n", ifMsg.ifm_type);
794 if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO)) {
795 LIST_FOREACH(mip, &root, list) {
797 if (ifMsg.ifm_index == mip->ifIndex) {
799 printf("Interface address/MTU has probably changed.\n");
800 mip->assignAliasAddr = 1;
806 static void PrintPacket (struct ip* ip)
808 printf ("%s", FormatPacket (ip));
811 static void SyslogPacket (struct ip* ip, int priority, const char *label)
813 syslog (priority, "%s %s", label, FormatPacket (ip));
816 static char* FormatPacket (struct ip* ip)
818 static char buf[256];
819 struct tcphdr* tcphdr;
820 struct udphdr* udphdr;
821 struct icmp* icmphdr;
825 strcpy (src, inet_ntoa (ip->ip_src));
826 strcpy (dst, inet_ntoa (ip->ip_dst));
830 tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2));
831 sprintf (buf, "[TCP] %s:%d -> %s:%d",
833 ntohs (tcphdr->th_sport),
835 ntohs (tcphdr->th_dport));
839 udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2));
840 sprintf (buf, "[UDP] %s:%d -> %s:%d",
842 ntohs (udphdr->uh_sport),
844 ntohs (udphdr->uh_dport));
848 icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2));
849 sprintf (buf, "[ICMP] %s -> %s %u(%u)",
857 sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst);
865 SetAliasAddressFromIfName(const char *ifn)
869 char *buf, *lim, *next;
870 struct if_msghdr *ifm;
871 struct ifa_msghdr *ifam;
872 struct sockaddr_dl *sdl;
873 struct sockaddr_in *sin;
878 mib[3] = AF_INET; /* Only IP addresses please */
879 mib[4] = NET_RT_IFLIST;
880 mib[5] = 0; /* ifIndex??? */
882 * Get interface data.
884 if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
885 err(1, "iflist-sysctl-estimate");
886 if ((buf = malloc(needed)) == NULL)
887 errx(1, "malloc failed");
888 if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
889 err(1, "iflist-sysctl-get");
892 * Loop through interfaces until one with
893 * given name is found. This is done to
894 * find correct interface index for routing
895 * message processing.
900 ifm = (struct if_msghdr *)next;
901 next += ifm->ifm_msglen;
902 if (ifm->ifm_version != RTM_VERSION) {
904 warnx("routing message version %d "
905 "not understood", ifm->ifm_version);
908 if (ifm->ifm_type == RTM_IFINFO) {
909 sdl = (struct sockaddr_dl *)(ifm + 1);
910 if (strlen(ifn) == sdl->sdl_nlen &&
911 strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) {
912 mip->ifIndex = ifm->ifm_index;
913 mip->ifMTU = ifm->ifm_data.ifi_mtu;
919 errx(1, "unknown interface name %s", ifn);
921 * Get interface address.
925 ifam = (struct ifa_msghdr *)next;
926 next += ifam->ifam_msglen;
927 if (ifam->ifam_version != RTM_VERSION) {
929 warnx("routing message version %d "
930 "not understood", ifam->ifam_version);
933 if (ifam->ifam_type != RTM_NEWADDR)
935 if (ifam->ifam_addrs & RTA_IFA) {
937 char *cp = (char *)(ifam + 1);
939 for (i = 1; i < RTA_IFA; i <<= 1)
940 if (ifam->ifam_addrs & i)
941 cp += SA_SIZE((struct sockaddr *)cp);
942 if (((struct sockaddr *)cp)->sa_family == AF_INET) {
943 sin = (struct sockaddr_in *)cp;
949 errx(1, "%s: cannot get interface address", ifn);
951 LibAliasSetAddress(mla, sin->sin_addr);
952 syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes",
953 inet_ntoa(sin->sin_addr), mip->ifMTU);
958 void Quit (const char* msg)
964 void Warn (const char* msg)
967 syslog (LOG_ALERT, "%s (%m)", msg);
972 static void RefreshAddr (int sig __unused)
974 LibAliasRefreshModules();
975 if (mip != NULL && mip->ifName != NULL)
976 mip->assignAliasAddr = 1;
979 static void InitiateShutdown (int sig __unused)
982 * Start timer to allow kernel gracefully
983 * shutdown existing connections when system
986 siginterrupt(SIGALRM, 1);
987 signal (SIGALRM, Shutdown);
991 static void Shutdown (int sig __unused)
997 * Different options recognized by this program.
1037 * Option information structure (used by ParseOption).
1045 const char* parmDescription;
1046 const char* description;
1048 const char* shortName;
1052 * Table of known options.
1055 static struct OptionInfo optionTable[] = {
1058 PKT_ALIAS_UNREGISTERED_ONLY,
1061 "alias only unregistered addresses",
1062 "unregistered_only",
1074 PKT_ALIAS_PROXY_ONLY,
1085 "operate in reverse mode",
1090 PKT_ALIAS_DENY_INCOMING,
1093 "allow incoming connections",
1098 PKT_ALIAS_USE_SOCKETS,
1101 "use sockets to inhibit port conflict",
1106 PKT_ALIAS_SAME_PORTS,
1109 "try to keep original port numbers for connections",
1117 "verbose mode, dump packet information",
1125 "dynamic mode, automatically detect interface address changes",
1132 "number|service_name",
1133 "set port for incoming packets",
1140 "number|service_name",
1141 "set port for outgoing packets",
1148 "number|service_name",
1149 "set port (defaults to natd/divert)",
1156 "number|service_name",
1165 "address to use for aliasing",
1173 "address to use for incoming sessions",
1181 "take aliasing address from interface",
1188 "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
1190 "add transparent proxying / destination NAT",
1197 "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
1198 " [remote_addr[:remote_port_range]]",
1199 "redirect a port (or ports) for incoming traffic",
1206 "proto local_addr [public_addr] [remote_addr]",
1207 "redirect packets of a given proto",
1214 "local_addr[,...] public_addr",
1215 "define mapping between local and public addresses",
1223 "read options from configuration file",
1231 "enable logging of denied incoming packets",
1239 "name of syslog facility to use for logging",
1247 "punch holes in the firewall for incoming FTP/IRC DCC connections",
1255 "set the TCP port for use with the Skinny Station protocol",
1263 "log packets converted by natd, but denied by ipfw",
1271 "store PID in an alternate file",
1278 "name of aliasing engine instance",
1283 static void ParseOption (const char* option, const char* parms)
1286 struct OptionInfo* info;
1291 const char* strValue;
1292 struct in_addr addrValue;
1295 CODE* fac_record = NULL;
1297 * Find option from table.
1299 max = sizeof (optionTable) / sizeof (struct OptionInfo);
1300 for (i = 0, info = optionTable; i < max; i++, info++) {
1302 if (!strcmp (info->name, option))
1305 if (info->shortName)
1306 if (!strcmp (info->shortName, option))
1312 warnx ("unknown option %s", option);
1323 switch (info->parm) {
1328 if (!strcmp (parms, "yes"))
1331 if (!strcmp (parms, "no"))
1334 errx (1, "%s needs yes/no parameter", option);
1339 errx (1, "%s needs service name or "
1340 "port number parameter",
1343 uNumValue = StrToPort (parms, "divert");
1348 numValue = strtol (parms, &end, 10);
1353 errx (1, "%s needs numeric parameter", option);
1359 errx (1, "%s needs parameter", option);
1364 errx (1, "%s does not take parameters", option);
1369 errx (1, "%s needs address/host parameter", option);
1371 StrToAddr (parms, &addrValue);
1375 switch (info->type) {
1376 case LibAliasOption:
1378 aliasValue = yesNoValue ? info->packetAliasOpt : 0;
1379 LibAliasSetMode (mla, aliasValue, info->packetAliasOpt);
1383 verbose = yesNoValue;
1387 dynamicMode = yesNoValue;
1391 mip->inPort = uNumValue;
1395 mip->outPort = uNumValue;
1399 mip->inOutPort = uNumValue;
1403 globalPort = uNumValue;
1407 memcpy (&mip->aliasAddr, &addrValue, sizeof (struct in_addr));
1411 LibAliasSetTarget(mla, addrValue);
1415 SetupPortRedirect (strValue);
1419 SetupProtoRedirect(strValue);
1422 case RedirectAddress:
1423 SetupAddressRedirect (strValue);
1427 LibAliasProxyRule (mla, strValue);
1434 mip->ifName = strdup (strValue);
1438 ReadConfigFile (strValue);
1442 mip->logDropped = yesNoValue;
1447 fac_record = facilitynames;
1448 while (fac_record->c_name != NULL) {
1450 if (!strcmp (fac_record->c_name, strValue)) {
1452 logFacility = fac_record->c_val;
1460 if(fac_record->c_name == NULL)
1461 errx(1, "Unknown log facility name: %s", strValue);
1466 SetupPunchFW(strValue);
1470 SetupSkinnyPort(strValue);
1474 logIpfwDenied = yesNoValue;;
1478 pidName = strdup (strValue);
1481 NewInstance(strValue);
1486 void ReadConfigFile (const char* fileName)
1494 file = fopen (fileName, "r");
1496 err(1, "cannot open config file %s", fileName);
1498 while ((buf = fgetln(file, &len)) != NULL) {
1499 if (buf[len - 1] == '\n')
1500 buf[len - 1] = '\0';
1502 errx(1, "config file format error: "
1503 "last line should end with newline");
1506 * Check for comments, strip off trailing spaces.
1508 if ((ptr = strchr(buf, '#')))
1510 for (ptr = buf; isspace(*ptr); ++ptr)
1514 for (p = strchr(buf, '\0'); isspace(*--p);)
1519 * Extract option name.
1522 while (*ptr && !isspace (*ptr))
1531 * Skip white space between name and parms.
1533 while (*ptr && isspace (*ptr))
1536 ParseOption (option, *ptr ? ptr : NULL);
1542 static void Usage ()
1546 struct OptionInfo* info;
1548 fprintf (stderr, "Recognized options:\n\n");
1550 max = sizeof (optionTable) / sizeof (struct OptionInfo);
1551 for (i = 0, info = optionTable; i < max; i++, info++) {
1553 fprintf (stderr, "-%-20s %s\n", info->name,
1554 info->parmDescription);
1556 if (info->shortName)
1557 fprintf (stderr, "-%-20s %s\n", info->shortName,
1558 info->parmDescription);
1560 fprintf (stderr, " %s\n\n", info->description);
1566 void SetupPortRedirect (const char* parms)
1571 struct in_addr localAddr;
1572 struct in_addr publicAddr;
1573 struct in_addr remoteAddr;
1574 port_range portRange;
1575 u_short localPort = 0;
1576 u_short publicPort = 0;
1577 u_short remotePort = 0;
1578 u_short numLocalPorts = 0;
1579 u_short numPublicPorts = 0;
1580 u_short numRemotePorts = 0;
1585 struct alias_link *aliaslink = NULL;
1587 strlcpy (buf, parms, sizeof(buf));
1591 protoName = strtok (buf, " \t");
1593 errx (1, "redirect_port: missing protocol");
1595 proto = StrToProto (protoName);
1597 * Extract local address.
1599 ptr = strtok (NULL, " \t");
1601 errx (1, "redirect_port: missing local address");
1603 separator = strchr(ptr, ',');
1604 if (separator) { /* LSNAT redirection syntax. */
1605 localAddr.s_addr = INADDR_NONE;
1610 if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 )
1611 errx (1, "redirect_port: invalid local port range");
1613 localPort = GETLOPORT(portRange);
1614 numLocalPorts = GETNUMPORTS(portRange);
1619 * Extract public port and optionally address.
1621 ptr = strtok (NULL, " \t");
1623 errx (1, "redirect_port: missing public port");
1625 separator = strchr (ptr, ':');
1627 if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 )
1628 errx (1, "redirect_port: invalid public port range");
1631 publicAddr.s_addr = INADDR_ANY;
1632 if (StrToPortRange (ptr, protoName, &portRange) != 0)
1633 errx (1, "redirect_port: invalid public port range");
1636 publicPort = GETLOPORT(portRange);
1637 numPublicPorts = GETNUMPORTS(portRange);
1640 * Extract remote address and optionally port.
1642 ptr = strtok (NULL, " \t");
1644 separator = strchr (ptr, ':');
1646 if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0)
1647 errx (1, "redirect_port: invalid remote port range");
1649 SETLOPORT(portRange, 0);
1650 SETNUMPORTS(portRange, 1);
1651 StrToAddr (ptr, &remoteAddr);
1655 SETLOPORT(portRange, 0);
1656 SETNUMPORTS(portRange, 1);
1657 remoteAddr.s_addr = INADDR_ANY;
1660 remotePort = GETLOPORT(portRange);
1661 numRemotePorts = GETNUMPORTS(portRange);
1664 * Make sure port ranges match up, then add the redirect ports.
1666 if (numLocalPorts != numPublicPorts)
1667 errx (1, "redirect_port: port ranges must be equal in size");
1669 /* Remote port range is allowed to be '0' which means all ports. */
1670 if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0))
1671 errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
1673 for (i = 0 ; i < numPublicPorts ; ++i) {
1674 /* If remotePort is all ports, set it to 0. */
1675 u_short remotePortCopy = remotePort + i;
1676 if (numRemotePorts == 1 && remotePort == 0)
1679 aliaslink = LibAliasRedirectPort (mla, localAddr,
1680 htons(localPort + i),
1682 htons(remotePortCopy),
1684 htons(publicPort + i),
1689 * Setup LSNAT server pool.
1691 if (serverPool != NULL && aliaslink != NULL) {
1692 ptr = strtok(serverPool, ",");
1693 while (ptr != NULL) {
1694 if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0)
1695 errx(1, "redirect_port: invalid local port range");
1697 localPort = GETLOPORT(portRange);
1698 if (GETNUMPORTS(portRange) != 1)
1699 errx(1, "redirect_port: local port must be single in this context");
1700 LibAliasAddServer(mla, aliaslink, localAddr, htons(localPort));
1701 ptr = strtok(NULL, ",");
1707 SetupProtoRedirect(const char* parms)
1711 struct in_addr localAddr;
1712 struct in_addr publicAddr;
1713 struct in_addr remoteAddr;
1716 struct protoent *protoent;
1718 strlcpy (buf, parms, sizeof(buf));
1722 protoName = strtok(buf, " \t");
1724 errx(1, "redirect_proto: missing protocol");
1726 protoent = getprotobyname(protoName);
1727 if (protoent == NULL)
1728 errx(1, "redirect_proto: unknown protocol %s", protoName);
1730 proto = protoent->p_proto;
1732 * Extract local address.
1734 ptr = strtok(NULL, " \t");
1736 errx(1, "redirect_proto: missing local address");
1738 StrToAddr(ptr, &localAddr);
1740 * Extract optional public address.
1742 ptr = strtok(NULL, " \t");
1744 StrToAddr(ptr, &publicAddr);
1746 publicAddr.s_addr = INADDR_ANY;
1748 * Extract optional remote address.
1750 ptr = strtok(NULL, " \t");
1752 StrToAddr(ptr, &remoteAddr);
1754 remoteAddr.s_addr = INADDR_ANY;
1756 * Create aliasing link.
1758 (void)LibAliasRedirectProto(mla, localAddr, remoteAddr, publicAddr,
1762 void SetupAddressRedirect (const char* parms)
1767 struct in_addr localAddr;
1768 struct in_addr publicAddr;
1770 struct alias_link *aliaslink;
1772 strlcpy (buf, parms, sizeof(buf));
1774 * Extract local address.
1776 ptr = strtok (buf, " \t");
1778 errx (1, "redirect_address: missing local address");
1780 separator = strchr(ptr, ',');
1781 if (separator) { /* LSNAT redirection syntax. */
1782 localAddr.s_addr = INADDR_NONE;
1785 StrToAddr (ptr, &localAddr);
1789 * Extract public address.
1791 ptr = strtok (NULL, " \t");
1793 errx (1, "redirect_address: missing public address");
1795 StrToAddr (ptr, &publicAddr);
1796 aliaslink = LibAliasRedirectAddr(mla, localAddr, publicAddr);
1799 * Setup LSNAT server pool.
1801 if (serverPool != NULL && aliaslink != NULL) {
1802 ptr = strtok(serverPool, ",");
1803 while (ptr != NULL) {
1804 StrToAddr(ptr, &localAddr);
1805 LibAliasAddServer(mla, aliaslink, localAddr, htons(~0));
1806 ptr = strtok(NULL, ",");
1811 void StrToAddr (const char* str, struct in_addr* addr)
1815 if (inet_aton (str, addr))
1818 hp = gethostbyname (str);
1820 errx (1, "unknown host %s", str);
1822 memcpy (addr, hp->h_addr, sizeof (struct in_addr));
1825 u_short StrToPort (const char* str, const char* proto)
1831 port = strtol (str, &end, 10);
1833 return htons (port);
1835 sp = getservbyname (str, proto);
1837 errx (1, "%s/%s: unknown service", str, proto);
1842 int StrToPortRange (const char* str, const char* proto, port_range *portRange)
1850 /* First see if this is a service, return corresponding port if so. */
1851 sp = getservbyname (str,proto);
1853 SETLOPORT(*portRange, ntohs(sp->s_port));
1854 SETNUMPORTS(*portRange, 1);
1858 /* Not a service, see if it's a single port or port range. */
1859 sep = strchr (str, '-');
1861 SETLOPORT(*portRange, strtol(str, &end, 10));
1864 SETNUMPORTS(*portRange, 1);
1868 /* Error in port range field. */
1869 errx (1, "%s/%s: unknown service", str, proto);
1872 /* Port range, get the values and sanity check. */
1873 sscanf (str, "%hu-%hu", &loPort, &hiPort);
1874 SETLOPORT(*portRange, loPort);
1875 SETNUMPORTS(*portRange, 0); /* Error by default */
1876 if (loPort <= hiPort)
1877 SETNUMPORTS(*portRange, hiPort - loPort + 1);
1879 if (GETNUMPORTS(*portRange) == 0)
1880 errx (1, "invalid port range %s", str);
1886 int StrToProto (const char* str)
1888 if (!strcmp (str, "tcp"))
1891 if (!strcmp (str, "udp"))
1894 errx (1, "unknown protocol %s. Expected tcp or udp", str);
1897 int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange)
1901 ptr = strchr (str, ':');
1903 errx (1, "%s is missing port number", str);
1908 StrToAddr (str, addr);
1909 return StrToPortRange (ptr, proto, portRange);
1913 SetupPunchFW(const char *strValue)
1915 unsigned int base, num;
1917 if (sscanf(strValue, "%u:%u", &base, &num) != 2)
1918 errx(1, "punch_fw: basenumber:count parameter required");
1920 if (CheckIpfwRulenum(base + num - 1) == -1)
1921 errx(1, "punch_fw: basenumber:count parameter should fit "
1922 "the maximum allowed rule numbers");
1924 LibAliasSetFWBase(mla, base, num);
1925 (void)LibAliasSetMode(mla, PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);
1929 SetupSkinnyPort(const char *strValue)
1933 if (sscanf(strValue, "%u", &port) != 1)
1934 errx(1, "skinny_port: port parameter required");
1936 LibAliasSetSkinnyPort(mla, port);
1940 NewInstance(const char *name)
1942 struct instance *ip;
1944 LIST_FOREACH(ip, &root, list) {
1945 if (!strcmp(ip->name, name)) {
1952 ip = calloc(sizeof *ip, 1);
1953 ip->name = strdup(name);
1954 ip->la = LibAliasInit (ip->la);
1955 ip->assignAliasAddr = 0;
1961 ip->aliasAddr.s_addr = INADDR_NONE;
1963 ip->aliasOverhead = 12;
1964 LIST_INSERT_HEAD(&root, ip, list);
1970 CheckIpfwRulenum(unsigned int rnum)
1972 unsigned int default_rule;
1973 size_t len = sizeof(default_rule);
1975 if (sysctlbyname("net.inet.ip.fw.default_rule", &default_rule, &len,
1977 warn("Failed to get the default ipfw rule number, using "
1978 "default historical value 65535. The reason was");
1979 default_rule = 65535;
1981 if (rnum >= default_rule) {