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);
139 static int background;
141 static int logFacility;
143 static int dynamicMode;
145 static int logIpfwDenied;
146 static const char* pidName;
147 static int routeSock;
148 static int globalPort;
149 static int divertGlobal;
151 int main (int argc, char** argv)
153 struct sockaddr_in addr;
157 * Initialize packet aliasing software.
158 * Done already here to be able to alter option bits
159 * during command line and configuration file processing.
161 NewInstance("default");
170 logFacility = LOG_DAEMON;
178 ParseArgs (argc, argv);
180 * Log ipfw(8) denied packets by default in verbose mode.
182 if (logIpfwDenied == -1)
183 logIpfwDenied = verbose;
185 * Open syslog channel.
187 openlog ("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0),
190 LIST_FOREACH(mip, &root, list) {
193 * If not doing the transparent proxying only,
194 * check that valid aliasing address has been given.
196 if (mip->aliasAddr.s_addr == INADDR_NONE && mip->ifName == NULL &&
197 !(LibAliasSetMode(mla, 0,0) & PKT_ALIAS_PROXY_ONLY))
198 errx (1, "instance %s: aliasing address not given", mip->name);
200 if (mip->aliasAddr.s_addr != INADDR_NONE && mip->ifName != NULL)
201 errx (1, "both alias address and interface "
202 "name are not allowed");
204 * Check that valid port number is known.
206 if (mip->inPort != 0 || mip->outPort != 0)
207 if (mip->inPort == 0 || mip->outPort == 0)
208 errx (1, "both input and output ports are required");
210 if (mip->inPort == 0 && mip->outPort == 0 && mip->inOutPort == 0)
211 ParseOption ("port", DEFAULT_SERVICE);
214 * Check if ignored packets should be dropped.
216 mip->dropIgnoredIncoming = LibAliasSetMode (mla, 0, 0);
217 mip->dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING;
219 * Create divert sockets. Use only one socket if -p was specified
220 * on command line. Otherwise, create separate sockets for
221 * outgoing and incoming connnections.
223 if (mip->inOutPort) {
225 mip->divertInOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
226 if (mip->divertInOut == -1)
227 Quit ("Unable to create divert socket.");
228 if (mip->divertInOut > fdMax)
229 fdMax = mip->divertInOut;
237 addr.sin_family = AF_INET;
238 addr.sin_addr.s_addr = INADDR_ANY;
239 addr.sin_port = mip->inOutPort;
241 if (bind (mip->divertInOut,
242 (struct sockaddr*) &addr,
244 Quit ("Unable to bind divert socket.");
248 mip->divertIn = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
249 if (mip->divertIn == -1)
250 Quit ("Unable to create incoming divert socket.");
251 if (mip->divertIn > fdMax)
252 fdMax = mip->divertIn;
255 mip->divertOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
256 if (mip->divertOut == -1)
257 Quit ("Unable to create outgoing divert socket.");
258 if (mip->divertOut > fdMax)
259 fdMax = mip->divertOut;
261 mip->divertInOut = -1;
264 * Bind divert sockets.
267 addr.sin_family = AF_INET;
268 addr.sin_addr.s_addr = INADDR_ANY;
269 addr.sin_port = mip->inPort;
271 if (bind (mip->divertIn,
272 (struct sockaddr*) &addr,
274 Quit ("Unable to bind incoming divert socket.");
276 addr.sin_family = AF_INET;
277 addr.sin_addr.s_addr = INADDR_ANY;
278 addr.sin_port = mip->outPort;
280 if (bind (mip->divertOut,
281 (struct sockaddr*) &addr,
283 Quit ("Unable to bind outgoing divert socket.");
286 * Create routing socket if interface name specified and in dynamic mode.
292 routeSock = socket (PF_ROUTE, SOCK_RAW, 0);
294 Quit ("Unable to create routing info socket.");
295 if (routeSock > fdMax)
298 mip->assignAliasAddr = 1;
301 SetAliasAddressFromIfName (mip->ifName);
307 divertGlobal = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
308 if (divertGlobal == -1)
309 Quit ("Unable to create divert socket.");
310 if (divertGlobal > fdMax)
311 fdMax = divertGlobal;
317 addr.sin_family = AF_INET;
318 addr.sin_addr.s_addr = INADDR_ANY;
319 addr.sin_port = globalPort;
321 if (bind (divertGlobal,
322 (struct sockaddr*) &addr,
324 Quit ("Unable to bind global divert socket.");
327 * Create socket for sending ICMP messages.
329 icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
331 Quit ("Unable to create ICMP socket.");
334 * And disable reads for the socket, otherwise it slowly fills
335 * up with received icmps which we do not use.
337 shutdown(icmpSock, SHUT_RD);
340 * Become a daemon unless verbose mode was requested.
345 * Catch signals to manage shutdown and
346 * refresh of interface address.
348 siginterrupt(SIGTERM, 1);
349 siginterrupt(SIGHUP, 1);
350 signal (SIGTERM, InitiateShutdown);
351 signal (SIGHUP, RefreshAddr);
353 * Set alias address if it has been given.
355 mip = LIST_FIRST(&root); /* XXX: simon */
356 LIST_FOREACH(mip, &root, list) {
358 if (mip->aliasAddr.s_addr != INADDR_NONE)
359 LibAliasSetAddress (mla, mip->aliasAddr);
363 mip = LIST_FIRST(&root); /* XXX: simon */
365 if (mip->divertInOut != -1 && !mip->ifName && ninstance == 1) {
367 * When using only one socket, just call
368 * DoAliasing repeatedly to process packets.
370 DoAliasing (mip->divertInOut, DONT_KNOW);
374 * Build read mask from socket descriptors to select.
378 * Check if new packets are available.
380 LIST_FOREACH(mip, &root, list) {
381 if (mip->divertIn != -1)
382 FD_SET (mip->divertIn, &readMask);
384 if (mip->divertOut != -1)
385 FD_SET (mip->divertOut, &readMask);
387 if (mip->divertInOut != -1)
388 FD_SET (mip->divertInOut, &readMask);
391 * Routing info is processed always.
394 FD_SET (routeSock, &readMask);
396 if (divertGlobal != -1)
397 FD_SET (divertGlobal, &readMask);
399 if (select (fdMax + 1,
408 Quit ("Select failed.");
411 if (divertGlobal != -1)
412 if (FD_ISSET (divertGlobal, &readMask))
413 DoGlobal (divertGlobal);
414 LIST_FOREACH(mip, &root, list) {
416 if (mip->divertIn != -1)
417 if (FD_ISSET (mip->divertIn, &readMask))
418 DoAliasing (mip->divertIn, INPUT);
420 if (mip->divertOut != -1)
421 if (FD_ISSET (mip->divertOut, &readMask))
422 DoAliasing (mip->divertOut, OUTPUT);
424 if (mip->divertInOut != -1)
425 if (FD_ISSET (mip->divertInOut, &readMask))
426 DoAliasing (mip->divertInOut, DONT_KNOW);
430 if (FD_ISSET (routeSock, &readMask))
431 HandleRoutingInfo (routeSock);
440 static void DaemonMode ()
447 pidFile = fopen (pidName, "w");
450 fprintf (pidFile, "%d\n", getpid ());
455 static void ParseArgs (int argc, char** argv)
460 int len; /* bounds checking */
462 for (arg = 1; arg < argc; arg++) {
467 warnx ("invalid option %s", opt);
474 while (arg < argc - 1) {
476 if (argv[arg + 1][0] == '-')
480 strncat (parmBuf, " ", sizeof(parmBuf) - (len + 1));
481 len += strlen(parmBuf + len);
485 strncat (parmBuf, argv[arg], sizeof(parmBuf) - (len + 1));
486 len += strlen(parmBuf + len);
490 ParseOption (opt + 1, (len ? parmBuf : NULL));
495 static void DoGlobal (int fd)
499 char buf[IP_MAXPACKET];
500 struct sockaddr_in addr;
507 * Get packet from socket.
509 addrSize = sizeof addr;
510 origBytes = recvfrom (fd,
514 (struct sockaddr*) &addr,
517 if (origBytes == -1) {
520 Warn ("read from divert socket failed");
526 if (mip->assignAliasAddr) {
527 SetAliasAddressFromIfName (mip->ifName);
528 mip->assignAliasAddr = 0;
532 * This is an IP packet.
534 ip = (struct ip*) buf;
538 * Print packet direction and protocol type.
556 printf ("[%d] ", ip->ip_p);
565 LIST_FOREACH(mip, &root, list) {
567 if (LibAliasOutTry (mla, buf, IP_MAXPACKET, 0) != PKT_ALIAS_IGNORED)
571 * Length might have changed during aliasing.
573 bytes = ntohs (ip->ip_len);
575 * Update alias overhead size for outgoing packets.
577 if (mip != NULL && bytes - origBytes > mip->aliasOverhead)
578 mip->aliasOverhead = bytes - origBytes;
583 * Print addresses after aliasing.
585 printf (" aliased to\n");
592 * Put packet back for processing.
598 (struct sockaddr*) &addr,
601 if (wrote != bytes) {
603 if (errno == EMSGSIZE) {
605 if (mip->ifMTU != -1)
606 SendNeedFragIcmp (icmpSock,
608 mip->ifMTU - mip->aliasOverhead);
610 else if (errno == EACCES && logIpfwDenied) {
612 sprintf (msgBuf, "failed to write packet back");
619 static void DoAliasing (int fd, int direction)
623 char buf[IP_MAXPACKET];
624 struct sockaddr_in addr;
631 if (mip->assignAliasAddr) {
633 SetAliasAddressFromIfName (mip->ifName);
634 mip->assignAliasAddr = 0;
637 * Get packet from socket.
639 addrSize = sizeof addr;
640 origBytes = recvfrom (fd,
644 (struct sockaddr*) &addr,
647 if (origBytes == -1) {
650 Warn ("read from divert socket failed");
655 * This is an IP packet.
657 ip = (struct ip*) buf;
658 if (direction == DONT_KNOW) {
659 if (addr.sin_addr.s_addr == INADDR_ANY)
667 * Print packet direction and protocol type.
669 printf (direction == OUTPUT ? "Out " : "In ");
671 printf ("{%s}", mip->name);
687 printf ("[%d] ", ip->ip_p);
696 if (direction == OUTPUT) {
698 * Outgoing packets. Do aliasing.
700 LibAliasOut (mla, buf, IP_MAXPACKET);
707 status = LibAliasIn (mla, buf, IP_MAXPACKET);
708 if (status == PKT_ALIAS_IGNORED &&
709 mip->dropIgnoredIncoming) {
712 printf (" dropped.\n");
715 SyslogPacket (ip, LOG_WARNING, "denied");
721 * Length might have changed during aliasing.
723 bytes = ntohs (ip->ip_len);
725 * Update alias overhead size for outgoing packets.
727 if (direction == OUTPUT &&
728 bytes - origBytes > mip->aliasOverhead)
729 mip->aliasOverhead = bytes - origBytes;
734 * Print addresses after aliasing.
736 printf (" aliased to\n");
743 * Put packet back for processing.
749 (struct sockaddr*) &addr,
752 if (wrote != bytes) {
754 if (errno == EMSGSIZE) {
756 if (direction == OUTPUT &&
758 SendNeedFragIcmp (icmpSock,
760 mip->ifMTU - mip->aliasOverhead);
762 else if (errno == EACCES && logIpfwDenied) {
764 sprintf (msgBuf, "failed to write packet back");
770 static void HandleRoutingInfo (int fd)
773 struct if_msghdr ifMsg;
775 * Get packet from socket.
777 bytes = read (fd, &ifMsg, sizeof ifMsg);
780 Warn ("read from routing socket failed");
784 if (ifMsg.ifm_version != RTM_VERSION) {
786 Warn ("unexpected packet read from routing socket");
791 printf ("Routing message %#x received.\n", ifMsg.ifm_type);
793 if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO)) {
794 LIST_FOREACH(mip, &root, list) {
796 if (ifMsg.ifm_index == mip->ifIndex) {
798 printf("Interface address/MTU has probably changed.\n");
799 mip->assignAliasAddr = 1;
805 static void PrintPacket (struct ip* ip)
807 printf ("%s", FormatPacket (ip));
810 static void SyslogPacket (struct ip* ip, int priority, const char *label)
812 syslog (priority, "%s %s", label, FormatPacket (ip));
815 static char* FormatPacket (struct ip* ip)
817 static char buf[256];
818 struct tcphdr* tcphdr;
819 struct udphdr* udphdr;
820 struct icmp* icmphdr;
824 strcpy (src, inet_ntoa (ip->ip_src));
825 strcpy (dst, inet_ntoa (ip->ip_dst));
829 tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2));
830 sprintf (buf, "[TCP] %s:%d -> %s:%d",
832 ntohs (tcphdr->th_sport),
834 ntohs (tcphdr->th_dport));
838 udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2));
839 sprintf (buf, "[UDP] %s:%d -> %s:%d",
841 ntohs (udphdr->uh_sport),
843 ntohs (udphdr->uh_dport));
847 icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2));
848 sprintf (buf, "[ICMP] %s -> %s %u(%u)",
856 sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst);
864 SetAliasAddressFromIfName(const char *ifn)
868 char *buf, *lim, *next;
869 struct if_msghdr *ifm;
870 struct ifa_msghdr *ifam;
871 struct sockaddr_dl *sdl;
872 struct sockaddr_in *sin;
877 mib[3] = AF_INET; /* Only IP addresses please */
878 mib[4] = NET_RT_IFLIST;
879 mib[5] = 0; /* ifIndex??? */
881 * Get interface data.
883 if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
884 err(1, "iflist-sysctl-estimate");
885 if ((buf = malloc(needed)) == NULL)
886 errx(1, "malloc failed");
887 if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
888 err(1, "iflist-sysctl-get");
891 * Loop through interfaces until one with
892 * given name is found. This is done to
893 * find correct interface index for routing
894 * message processing.
899 ifm = (struct if_msghdr *)next;
900 next += ifm->ifm_msglen;
901 if (ifm->ifm_version != RTM_VERSION) {
903 warnx("routing message version %d "
904 "not understood", ifm->ifm_version);
907 if (ifm->ifm_type == RTM_IFINFO) {
908 sdl = (struct sockaddr_dl *)(ifm + 1);
909 if (strlen(ifn) == sdl->sdl_nlen &&
910 strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) {
911 mip->ifIndex = ifm->ifm_index;
912 mip->ifMTU = ifm->ifm_data.ifi_mtu;
918 errx(1, "unknown interface name %s", ifn);
920 * Get interface address.
924 ifam = (struct ifa_msghdr *)next;
925 next += ifam->ifam_msglen;
926 if (ifam->ifam_version != RTM_VERSION) {
928 warnx("routing message version %d "
929 "not understood", ifam->ifam_version);
932 if (ifam->ifam_type != RTM_NEWADDR)
934 if (ifam->ifam_addrs & RTA_IFA) {
936 char *cp = (char *)(ifam + 1);
938 for (i = 1; i < RTA_IFA; i <<= 1)
939 if (ifam->ifam_addrs & i)
940 cp += SA_SIZE((struct sockaddr *)cp);
941 if (((struct sockaddr *)cp)->sa_family == AF_INET) {
942 sin = (struct sockaddr_in *)cp;
948 errx(1, "%s: cannot get interface address", ifn);
950 LibAliasSetAddress(mla, sin->sin_addr);
951 syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes",
952 inet_ntoa(sin->sin_addr), mip->ifMTU);
957 void Quit (const char* msg)
963 void Warn (const char* msg)
966 syslog (LOG_ALERT, "%s (%m)", msg);
971 static void RefreshAddr (int sig __unused)
974 mip->assignAliasAddr = 1;
977 static void InitiateShutdown (int sig __unused)
980 * Start timer to allow kernel gracefully
981 * shutdown existing connections when system
984 siginterrupt(SIGALRM, 1);
985 signal (SIGALRM, Shutdown);
989 static void Shutdown (int sig __unused)
995 * Different options recognized by this program.
1035 * Option information structure (used by ParseOption).
1043 const char* parmDescription;
1044 const char* description;
1046 const char* shortName;
1050 * Table of known options.
1053 static struct OptionInfo optionTable[] = {
1056 PKT_ALIAS_UNREGISTERED_ONLY,
1059 "alias only unregistered addresses",
1060 "unregistered_only",
1072 PKT_ALIAS_PROXY_ONLY,
1083 "operate in reverse mode",
1088 PKT_ALIAS_DENY_INCOMING,
1091 "allow incoming connections",
1096 PKT_ALIAS_USE_SOCKETS,
1099 "use sockets to inhibit port conflict",
1104 PKT_ALIAS_SAME_PORTS,
1107 "try to keep original port numbers for connections",
1115 "verbose mode, dump packet information",
1123 "dynamic mode, automatically detect interface address changes",
1130 "number|service_name",
1131 "set port for incoming packets",
1138 "number|service_name",
1139 "set port for outgoing packets",
1146 "number|service_name",
1147 "set port (defaults to natd/divert)",
1154 "number|service_name",
1163 "address to use for aliasing",
1171 "address to use for incoming sessions",
1179 "take aliasing address from interface",
1186 "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
1188 "add transparent proxying / destination NAT",
1195 "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
1196 " [remote_addr[:remote_port_range]]",
1197 "redirect a port (or ports) for incoming traffic",
1204 "proto local_addr [public_addr] [remote_addr]",
1205 "redirect packets of a given proto",
1212 "local_addr[,...] public_addr",
1213 "define mapping between local and public addresses",
1221 "read options from configuration file",
1229 "enable logging of denied incoming packets",
1237 "name of syslog facility to use for logging",
1245 "punch holes in the firewall for incoming FTP/IRC DCC connections",
1253 "set the TCP port for use with the Skinny Station protocol",
1261 "log packets converted by natd, but denied by ipfw",
1269 "store PID in an alternate file",
1276 "name of aliasing engine instance",
1281 static void ParseOption (const char* option, const char* parms)
1284 struct OptionInfo* info;
1289 const char* strValue;
1290 struct in_addr addrValue;
1293 CODE* fac_record = NULL;
1295 * Find option from table.
1297 max = sizeof (optionTable) / sizeof (struct OptionInfo);
1298 for (i = 0, info = optionTable; i < max; i++, info++) {
1300 if (!strcmp (info->name, option))
1303 if (info->shortName)
1304 if (!strcmp (info->shortName, option))
1310 warnx ("unknown option %s", option);
1321 switch (info->parm) {
1326 if (!strcmp (parms, "yes"))
1329 if (!strcmp (parms, "no"))
1332 errx (1, "%s needs yes/no parameter", option);
1337 errx (1, "%s needs service name or "
1338 "port number parameter",
1341 uNumValue = StrToPort (parms, "divert");
1346 numValue = strtol (parms, &end, 10);
1351 errx (1, "%s needs numeric parameter", option);
1357 errx (1, "%s needs parameter", option);
1362 errx (1, "%s does not take parameters", option);
1367 errx (1, "%s needs address/host parameter", option);
1369 StrToAddr (parms, &addrValue);
1373 switch (info->type) {
1374 case LibAliasOption:
1376 aliasValue = yesNoValue ? info->packetAliasOpt : 0;
1377 LibAliasSetMode (mla, aliasValue, info->packetAliasOpt);
1381 verbose = yesNoValue;
1385 dynamicMode = yesNoValue;
1389 mip->inPort = uNumValue;
1393 mip->outPort = uNumValue;
1397 mip->inOutPort = uNumValue;
1401 globalPort = uNumValue;
1405 memcpy (&mip->aliasAddr, &addrValue, sizeof (struct in_addr));
1409 LibAliasSetTarget(mla, addrValue);
1413 SetupPortRedirect (strValue);
1417 SetupProtoRedirect(strValue);
1420 case RedirectAddress:
1421 SetupAddressRedirect (strValue);
1425 LibAliasProxyRule (mla, strValue);
1432 mip->ifName = strdup (strValue);
1436 ReadConfigFile (strValue);
1440 mip->logDropped = yesNoValue;
1445 fac_record = facilitynames;
1446 while (fac_record->c_name != NULL) {
1448 if (!strcmp (fac_record->c_name, strValue)) {
1450 logFacility = fac_record->c_val;
1458 if(fac_record->c_name == NULL)
1459 errx(1, "Unknown log facility name: %s", strValue);
1464 SetupPunchFW(strValue);
1468 SetupSkinnyPort(strValue);
1472 logIpfwDenied = yesNoValue;;
1476 pidName = strdup (strValue);
1479 NewInstance(strValue);
1484 void ReadConfigFile (const char* fileName)
1492 file = fopen (fileName, "r");
1494 err(1, "cannot open config file %s", fileName);
1496 while ((buf = fgetln(file, &len)) != NULL) {
1497 if (buf[len - 1] == '\n')
1498 buf[len - 1] = '\0';
1500 errx(1, "config file format error: "
1501 "last line should end with newline");
1504 * Check for comments, strip off trailing spaces.
1506 if ((ptr = strchr(buf, '#')))
1508 for (ptr = buf; isspace(*ptr); ++ptr)
1512 for (p = strchr(buf, '\0'); isspace(*--p);)
1517 * Extract option name.
1520 while (*ptr && !isspace (*ptr))
1529 * Skip white space between name and parms.
1531 while (*ptr && isspace (*ptr))
1534 ParseOption (option, *ptr ? ptr : NULL);
1540 static void Usage ()
1544 struct OptionInfo* info;
1546 fprintf (stderr, "Recognized options:\n\n");
1548 max = sizeof (optionTable) / sizeof (struct OptionInfo);
1549 for (i = 0, info = optionTable; i < max; i++, info++) {
1551 fprintf (stderr, "-%-20s %s\n", info->name,
1552 info->parmDescription);
1554 if (info->shortName)
1555 fprintf (stderr, "-%-20s %s\n", info->shortName,
1556 info->parmDescription);
1558 fprintf (stderr, " %s\n\n", info->description);
1564 void SetupPortRedirect (const char* parms)
1569 struct in_addr localAddr;
1570 struct in_addr publicAddr;
1571 struct in_addr remoteAddr;
1572 port_range portRange;
1573 u_short localPort = 0;
1574 u_short publicPort = 0;
1575 u_short remotePort = 0;
1576 u_short numLocalPorts = 0;
1577 u_short numPublicPorts = 0;
1578 u_short numRemotePorts = 0;
1583 struct alias_link *aliaslink = NULL;
1585 strlcpy (buf, parms, sizeof(buf));
1589 protoName = strtok (buf, " \t");
1591 errx (1, "redirect_port: missing protocol");
1593 proto = StrToProto (protoName);
1595 * Extract local address.
1597 ptr = strtok (NULL, " \t");
1599 errx (1, "redirect_port: missing local address");
1601 separator = strchr(ptr, ',');
1602 if (separator) { /* LSNAT redirection syntax. */
1603 localAddr.s_addr = INADDR_NONE;
1608 if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 )
1609 errx (1, "redirect_port: invalid local port range");
1611 localPort = GETLOPORT(portRange);
1612 numLocalPorts = GETNUMPORTS(portRange);
1617 * Extract public port and optionally address.
1619 ptr = strtok (NULL, " \t");
1621 errx (1, "redirect_port: missing public port");
1623 separator = strchr (ptr, ':');
1625 if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 )
1626 errx (1, "redirect_port: invalid public port range");
1629 publicAddr.s_addr = INADDR_ANY;
1630 if (StrToPortRange (ptr, protoName, &portRange) != 0)
1631 errx (1, "redirect_port: invalid public port range");
1634 publicPort = GETLOPORT(portRange);
1635 numPublicPorts = GETNUMPORTS(portRange);
1638 * Extract remote address and optionally port.
1640 ptr = strtok (NULL, " \t");
1642 separator = strchr (ptr, ':');
1644 if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0)
1645 errx (1, "redirect_port: invalid remote port range");
1647 SETLOPORT(portRange, 0);
1648 SETNUMPORTS(portRange, 1);
1649 StrToAddr (ptr, &remoteAddr);
1653 SETLOPORT(portRange, 0);
1654 SETNUMPORTS(portRange, 1);
1655 remoteAddr.s_addr = INADDR_ANY;
1658 remotePort = GETLOPORT(portRange);
1659 numRemotePorts = GETNUMPORTS(portRange);
1662 * Make sure port ranges match up, then add the redirect ports.
1664 if (numLocalPorts != numPublicPorts)
1665 errx (1, "redirect_port: port ranges must be equal in size");
1667 /* Remote port range is allowed to be '0' which means all ports. */
1668 if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0))
1669 errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
1671 for (i = 0 ; i < numPublicPorts ; ++i) {
1672 /* If remotePort is all ports, set it to 0. */
1673 u_short remotePortCopy = remotePort + i;
1674 if (numRemotePorts == 1 && remotePort == 0)
1677 aliaslink = LibAliasRedirectPort (mla, localAddr,
1678 htons(localPort + i),
1680 htons(remotePortCopy),
1682 htons(publicPort + i),
1687 * Setup LSNAT server pool.
1689 if (serverPool != NULL && aliaslink != NULL) {
1690 ptr = strtok(serverPool, ",");
1691 while (ptr != NULL) {
1692 if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0)
1693 errx(1, "redirect_port: invalid local port range");
1695 localPort = GETLOPORT(portRange);
1696 if (GETNUMPORTS(portRange) != 1)
1697 errx(1, "redirect_port: local port must be single in this context");
1698 LibAliasAddServer(mla, aliaslink, localAddr, htons(localPort));
1699 ptr = strtok(NULL, ",");
1705 SetupProtoRedirect(const char* parms)
1709 struct in_addr localAddr;
1710 struct in_addr publicAddr;
1711 struct in_addr remoteAddr;
1714 struct protoent *protoent;
1716 strlcpy (buf, parms, sizeof(buf));
1720 protoName = strtok(buf, " \t");
1722 errx(1, "redirect_proto: missing protocol");
1724 protoent = getprotobyname(protoName);
1725 if (protoent == NULL)
1726 errx(1, "redirect_proto: unknown protocol %s", protoName);
1728 proto = protoent->p_proto;
1730 * Extract local address.
1732 ptr = strtok(NULL, " \t");
1734 errx(1, "redirect_proto: missing local address");
1736 StrToAddr(ptr, &localAddr);
1738 * Extract optional public address.
1740 ptr = strtok(NULL, " \t");
1742 StrToAddr(ptr, &publicAddr);
1744 publicAddr.s_addr = INADDR_ANY;
1746 * Extract optional remote address.
1748 ptr = strtok(NULL, " \t");
1750 StrToAddr(ptr, &remoteAddr);
1752 remoteAddr.s_addr = INADDR_ANY;
1754 * Create aliasing link.
1756 (void)LibAliasRedirectProto(mla, localAddr, remoteAddr, publicAddr,
1760 void SetupAddressRedirect (const char* parms)
1765 struct in_addr localAddr;
1766 struct in_addr publicAddr;
1768 struct alias_link *aliaslink;
1770 strlcpy (buf, parms, sizeof(buf));
1772 * Extract local address.
1774 ptr = strtok (buf, " \t");
1776 errx (1, "redirect_address: missing local address");
1778 separator = strchr(ptr, ',');
1779 if (separator) { /* LSNAT redirection syntax. */
1780 localAddr.s_addr = INADDR_NONE;
1783 StrToAddr (ptr, &localAddr);
1787 * Extract public address.
1789 ptr = strtok (NULL, " \t");
1791 errx (1, "redirect_address: missing public address");
1793 StrToAddr (ptr, &publicAddr);
1794 aliaslink = LibAliasRedirectAddr(mla, localAddr, publicAddr);
1797 * Setup LSNAT server pool.
1799 if (serverPool != NULL && aliaslink != NULL) {
1800 ptr = strtok(serverPool, ",");
1801 while (ptr != NULL) {
1802 StrToAddr(ptr, &localAddr);
1803 LibAliasAddServer(mla, aliaslink, localAddr, htons(~0));
1804 ptr = strtok(NULL, ",");
1809 void StrToAddr (const char* str, struct in_addr* addr)
1813 if (inet_aton (str, addr))
1816 hp = gethostbyname (str);
1818 errx (1, "unknown host %s", str);
1820 memcpy (addr, hp->h_addr, sizeof (struct in_addr));
1823 u_short StrToPort (const char* str, const char* proto)
1829 port = strtol (str, &end, 10);
1831 return htons (port);
1833 sp = getservbyname (str, proto);
1835 errx (1, "%s/%s: unknown service", str, proto);
1840 int StrToPortRange (const char* str, const char* proto, port_range *portRange)
1848 /* First see if this is a service, return corresponding port if so. */
1849 sp = getservbyname (str,proto);
1851 SETLOPORT(*portRange, ntohs(sp->s_port));
1852 SETNUMPORTS(*portRange, 1);
1856 /* Not a service, see if it's a single port or port range. */
1857 sep = strchr (str, '-');
1859 SETLOPORT(*portRange, strtol(str, &end, 10));
1862 SETNUMPORTS(*portRange, 1);
1866 /* Error in port range field. */
1867 errx (1, "%s/%s: unknown service", str, proto);
1870 /* Port range, get the values and sanity check. */
1871 sscanf (str, "%hu-%hu", &loPort, &hiPort);
1872 SETLOPORT(*portRange, loPort);
1873 SETNUMPORTS(*portRange, 0); /* Error by default */
1874 if (loPort <= hiPort)
1875 SETNUMPORTS(*portRange, hiPort - loPort + 1);
1877 if (GETNUMPORTS(*portRange) == 0)
1878 errx (1, "invalid port range %s", str);
1884 int StrToProto (const char* str)
1886 if (!strcmp (str, "tcp"))
1889 if (!strcmp (str, "udp"))
1892 errx (1, "unknown protocol %s. Expected tcp or udp", str);
1895 int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange)
1899 ptr = strchr (str, ':');
1901 errx (1, "%s is missing port number", str);
1906 StrToAddr (str, addr);
1907 return StrToPortRange (ptr, proto, portRange);
1911 SetupPunchFW(const char *strValue)
1913 unsigned int base, num;
1915 if (sscanf(strValue, "%u:%u", &base, &num) != 2)
1916 errx(1, "punch_fw: basenumber:count parameter required");
1918 LibAliasSetFWBase(mla, base, num);
1919 (void)LibAliasSetMode(mla, PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);
1923 SetupSkinnyPort(const char *strValue)
1927 if (sscanf(strValue, "%u", &port) != 1)
1928 errx(1, "skinny_port: port parameter required");
1930 LibAliasSetSkinnyPort(mla, port);
1934 NewInstance(const char *name)
1936 struct instance *ip;
1938 LIST_FOREACH(ip, &root, list) {
1939 if (!strcmp(ip->name, name)) {
1946 ip = calloc(sizeof *ip, 1);
1947 ip->name = strdup(name);
1948 ip->la = LibAliasInit (ip->la);
1949 ip->assignAliasAddr = 0;
1955 ip->aliasAddr.s_addr = INADDR_NONE;
1957 ip->aliasOverhead = 12;
1958 LIST_INSERT_HEAD(&root, ip, list);