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>
16 #include <sys/types.h>
17 #include <sys/socket.h>
18 #include <sys/sysctl.h>
20 #include <sys/queue.h>
22 #include <netinet/in.h>
23 #include <netinet/in_systm.h>
24 #include <netinet/ip.h>
25 #include <netinet/tcp.h>
26 #include <netinet/udp.h>
27 #include <netinet/ip_icmp.h>
29 #include <net/if_dl.h>
30 #include <net/route.h>
31 #include <arpa/inet.h>
50 LIST_ENTRY(instance) list;
59 struct in_addr aliasAddr;
62 int dropIgnoredIncoming;
68 static LIST_HEAD(, instance) root = LIST_HEAD_INITIALIZER(root);
71 static struct instance *mip;
72 static int ninstance = 1;
75 * Default values for input and output
76 * divert socket ports.
79 #define DEFAULT_SERVICE "natd"
82 * Definition of a port range, and macros to deal with values.
83 * FORMAT: HI 16-bits == first port in range, 0 == all ports.
84 * LO 16-bits == number of ports in range
85 * NOTES: - Port values are not stored in network byte order.
88 typedef u_long port_range;
90 #define GETLOPORT(x) ((x) >> 0x10)
91 #define GETNUMPORTS(x) ((x) & 0x0000ffff)
92 #define GETHIPORT(x) (GETLOPORT((x)) + GETNUMPORTS((x)))
94 /* Set y to be the low-port value in port_range variable x. */
95 #define SETLOPORT(x,y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
97 /* Set y to be the number of ports in port_range variable x. */
98 #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y))
101 * Function prototypes.
104 static void DoAliasing (int fd, int direction);
105 static void DaemonMode (void);
106 static void HandleRoutingInfo (int fd);
107 static void Usage (void);
108 static char* FormatPacket (struct ip*);
109 static void PrintPacket (struct ip*);
110 static void SyslogPacket (struct ip*, int priority, const char *label);
111 static int SetAliasAddressFromIfName (const char *ifName);
112 static void InitiateShutdown (int);
113 static void Shutdown (int);
114 static void RefreshAddr (int);
115 static void ParseOption (const char* option, const char* parms);
116 static void ReadConfigFile (const char* fileName);
117 static void SetupPortRedirect (const char* parms);
118 static void SetupProtoRedirect(const char* parms);
119 static void SetupAddressRedirect (const char* parms);
120 static void StrToAddr (const char* str, struct in_addr* addr);
121 static u_short StrToPort (const char* str, const char* proto);
122 static int StrToPortRange (const char* str, const char* proto, port_range *portRange);
123 static int StrToProto (const char* str);
124 static int StrToAddrAndPortRange (char* str, struct in_addr* addr, char* proto, port_range *portRange);
125 static void ParseArgs (int argc, char** argv);
126 static void SetupPunchFW(const char *strValue);
127 static void SetupSkinnyPort(const char *strValue);
128 static void NewInstance(const char *name);
129 static void DoGlobal (int fd);
130 static int CheckIpfwRulenum(unsigned int rnum);
137 static int background;
139 static int logFacility;
141 static int dynamicMode;
143 static int logIpfwDenied;
144 static const char* pidName;
145 static int routeSock;
146 static int globalPort;
147 static int divertGlobal;
148 static int exitDelay;
151 int main (int argc, char** argv)
153 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;
178 exitDelay = EXIT_DELAY;
180 ParseArgs (argc, argv);
182 * Log ipfw(8) denied packets by default in verbose mode.
184 if (logIpfwDenied == -1)
185 logIpfwDenied = verbose;
187 * Open syslog channel.
189 openlog ("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0),
192 LIST_FOREACH(mip, &root, list) {
195 * If not doing the transparent proxying only,
196 * check that valid aliasing address has been given.
198 if (mip->aliasAddr.s_addr == INADDR_NONE && mip->ifName == NULL &&
199 !(LibAliasSetMode(mla, 0,0) & PKT_ALIAS_PROXY_ONLY))
200 errx (1, "instance %s: aliasing address not given", mip->name);
202 if (mip->aliasAddr.s_addr != INADDR_NONE && mip->ifName != NULL)
203 errx (1, "both alias address and interface "
204 "name are not allowed");
206 * Check that valid port number is known.
208 if (mip->inPort != 0 || mip->outPort != 0)
209 if (mip->inPort == 0 || mip->outPort == 0)
210 errx (1, "both input and output ports are required");
212 if (mip->inPort == 0 && mip->outPort == 0 && mip->inOutPort == 0)
213 ParseOption ("port", DEFAULT_SERVICE);
216 * Check if ignored packets should be dropped.
218 mip->dropIgnoredIncoming = LibAliasSetMode (mla, 0, 0);
219 mip->dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING;
221 * Create divert sockets. Use only one socket if -p was specified
222 * on command line. Otherwise, create separate sockets for
223 * outgoing and incoming connections.
225 if (mip->inOutPort) {
227 mip->divertInOut = socket(PF_DIVERT, SOCK_RAW, 0);
228 if (mip->divertInOut == -1)
229 Quit ("Unable to create divert socket.");
230 if (mip->divertInOut > fdMax)
231 fdMax = mip->divertInOut;
239 addr.sin_family = AF_INET;
240 addr.sin_addr.s_addr = INADDR_ANY;
241 addr.sin_port = mip->inOutPort;
243 if (bind (mip->divertInOut,
244 (struct sockaddr*) &addr,
246 Quit ("Unable to bind divert socket.");
250 mip->divertIn = socket(PF_DIVERT, SOCK_RAW, 0);
251 if (mip->divertIn == -1)
252 Quit ("Unable to create incoming divert socket.");
253 if (mip->divertIn > fdMax)
254 fdMax = mip->divertIn;
257 mip->divertOut = socket(PF_DIVERT, SOCK_RAW, 0);
258 if (mip->divertOut == -1)
259 Quit ("Unable to create outgoing divert socket.");
260 if (mip->divertOut > fdMax)
261 fdMax = mip->divertOut;
263 mip->divertInOut = -1;
266 * Bind divert sockets.
269 addr.sin_family = AF_INET;
270 addr.sin_addr.s_addr = INADDR_ANY;
271 addr.sin_port = mip->inPort;
273 if (bind (mip->divertIn,
274 (struct sockaddr*) &addr,
276 Quit ("Unable to bind incoming divert socket.");
278 addr.sin_family = AF_INET;
279 addr.sin_addr.s_addr = INADDR_ANY;
280 addr.sin_port = mip->outPort;
282 if (bind (mip->divertOut,
283 (struct sockaddr*) &addr,
285 Quit ("Unable to bind outgoing divert socket.");
288 * Create routing socket if interface name specified and in dynamic mode.
294 routeSock = socket (PF_ROUTE, SOCK_RAW, 0);
296 Quit ("Unable to create routing info socket.");
297 if (routeSock > fdMax)
300 mip->assignAliasAddr = 1;
304 rval = SetAliasAddressFromIfName (mip->ifName);
305 if (background == 0 || dynamicMode == 0)
309 } while (rval == EAGAIN);
318 divertGlobal = socket(PF_DIVERT, SOCK_RAW, 0);
319 if (divertGlobal == -1)
320 Quit ("Unable to create divert socket.");
321 if (divertGlobal > fdMax)
322 fdMax = divertGlobal;
328 addr.sin_family = AF_INET;
329 addr.sin_addr.s_addr = INADDR_ANY;
330 addr.sin_port = globalPort;
332 if (bind (divertGlobal,
333 (struct sockaddr*) &addr,
335 Quit ("Unable to bind global divert socket.");
338 * Create socket for sending ICMP messages.
340 icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
342 Quit ("Unable to create ICMP socket.");
345 * And disable reads for the socket, otherwise it slowly fills
346 * up with received icmps which we do not use.
348 shutdown(icmpSock, SHUT_RD);
351 * Become a daemon unless verbose mode was requested.
356 * Catch signals to manage shutdown and
357 * refresh of interface address.
359 siginterrupt(SIGTERM, 1);
360 siginterrupt(SIGHUP, 1);
362 signal(SIGTERM, InitiateShutdown);
364 signal(SIGTERM, Shutdown);
365 signal (SIGHUP, RefreshAddr);
367 * Set alias address if it has been given.
369 mip = LIST_FIRST(&root); /* XXX: simon */
370 LIST_FOREACH(mip, &root, list) {
372 if (mip->aliasAddr.s_addr != INADDR_NONE)
373 LibAliasSetAddress (mla, mip->aliasAddr);
377 mip = LIST_FIRST(&root); /* XXX: simon */
379 if (mip->divertInOut != -1 && !mip->ifName && ninstance == 1) {
381 * When using only one socket, just call
382 * DoAliasing repeatedly to process packets.
384 DoAliasing (mip->divertInOut, DONT_KNOW);
388 * Build read mask from socket descriptors to select.
392 * Check if new packets are available.
394 LIST_FOREACH(mip, &root, list) {
395 if (mip->divertIn != -1)
396 FD_SET (mip->divertIn, &readMask);
398 if (mip->divertOut != -1)
399 FD_SET (mip->divertOut, &readMask);
401 if (mip->divertInOut != -1)
402 FD_SET (mip->divertInOut, &readMask);
405 * Routing info is processed always.
408 FD_SET (routeSock, &readMask);
410 if (divertGlobal != -1)
411 FD_SET (divertGlobal, &readMask);
413 if (select (fdMax + 1,
422 Quit ("Select failed.");
425 if (divertGlobal != -1)
426 if (FD_ISSET (divertGlobal, &readMask))
427 DoGlobal (divertGlobal);
428 LIST_FOREACH(mip, &root, list) {
430 if (mip->divertIn != -1)
431 if (FD_ISSET (mip->divertIn, &readMask))
432 DoAliasing (mip->divertIn, INPUT);
434 if (mip->divertOut != -1)
435 if (FD_ISSET (mip->divertOut, &readMask))
436 DoAliasing (mip->divertOut, OUTPUT);
438 if (mip->divertInOut != -1)
439 if (FD_ISSET (mip->divertInOut, &readMask))
440 DoAliasing (mip->divertInOut, DONT_KNOW);
444 if (FD_ISSET (routeSock, &readMask))
445 HandleRoutingInfo (routeSock);
454 static void DaemonMode(void)
461 pidFile = fopen (pidName, "w");
464 fprintf (pidFile, "%d\n", getpid ());
469 static void ParseArgs (int argc, char** argv)
474 int len; /* bounds checking */
476 for (arg = 1; arg < argc; arg++) {
481 warnx ("invalid option %s", opt);
488 while (arg < argc - 1) {
490 if (argv[arg + 1][0] == '-')
494 strncat (parmBuf, " ", sizeof(parmBuf) - (len + 1));
495 len += strlen(parmBuf + len);
499 strncat (parmBuf, argv[arg], sizeof(parmBuf) - (len + 1));
500 len += strlen(parmBuf + len);
504 ParseOption (opt + 1, (len ? parmBuf : NULL));
509 static void DoGlobal (int fd)
513 char buf[IP_MAXPACKET];
514 struct sockaddr_in addr;
521 * Get packet from socket.
523 addrSize = sizeof addr;
524 origBytes = recvfrom (fd,
528 (struct sockaddr*) &addr,
531 if (origBytes == -1) {
534 Warn ("read from divert socket failed");
540 if (mip->assignAliasAddr) {
541 if (SetAliasAddressFromIfName (mip->ifName) != 0)
543 mip->assignAliasAddr = 0;
547 * This is an IP packet.
549 ip = (struct ip*) buf;
553 * Print packet direction and protocol type.
571 printf ("[%d] ", ip->ip_p);
580 LIST_FOREACH(mip, &root, list) {
582 if (LibAliasOutTry (mla, buf, IP_MAXPACKET, 0) != PKT_ALIAS_IGNORED)
586 * Length might have changed during aliasing.
588 bytes = ntohs (ip->ip_len);
590 * Update alias overhead size for outgoing packets.
592 if (mip != NULL && bytes - origBytes > mip->aliasOverhead)
593 mip->aliasOverhead = bytes - origBytes;
598 * Print addresses after aliasing.
600 printf (" aliased to\n");
607 * Put packet back for processing.
613 (struct sockaddr*) &addr,
616 if (wrote != bytes) {
618 if (errno == EMSGSIZE && mip != NULL) {
620 if (mip->ifMTU != -1)
621 SendNeedFragIcmp (icmpSock,
623 mip->ifMTU - mip->aliasOverhead);
625 else if (errno == EACCES && logIpfwDenied) {
627 sprintf (msgBuf, "failed to write packet back");
634 static void DoAliasing (int fd, int direction)
638 char buf[IP_MAXPACKET];
639 struct sockaddr_in addr;
647 if (mip->assignAliasAddr) {
649 rval = SetAliasAddressFromIfName (mip->ifName);
650 if (background == 0 || dynamicMode == 0)
654 } while (rval == EAGAIN);
657 mip->assignAliasAddr = 0;
660 * Get packet from socket.
662 addrSize = sizeof addr;
663 origBytes = recvfrom (fd,
667 (struct sockaddr*) &addr,
670 if (origBytes == -1) {
673 Warn ("read from divert socket failed");
678 * This is an IP packet.
680 ip = (struct ip*) buf;
681 if (direction == DONT_KNOW) {
682 if (addr.sin_addr.s_addr == INADDR_ANY)
690 * Print packet direction and protocol type.
692 printf (direction == OUTPUT ? "Out " : "In ");
694 printf ("{%s}", mip->name);
710 printf ("[%d] ", ip->ip_p);
719 if (direction == OUTPUT) {
721 * Outgoing packets. Do aliasing.
723 LibAliasOut (mla, buf, IP_MAXPACKET);
730 status = LibAliasIn (mla, buf, IP_MAXPACKET);
731 if (status == PKT_ALIAS_IGNORED &&
732 mip->dropIgnoredIncoming) {
735 printf (" dropped.\n");
738 SyslogPacket (ip, LOG_WARNING, "denied");
744 * Length might have changed during aliasing.
746 bytes = ntohs (ip->ip_len);
748 * Update alias overhead size for outgoing packets.
750 if (direction == OUTPUT &&
751 bytes - origBytes > mip->aliasOverhead)
752 mip->aliasOverhead = bytes - origBytes;
757 * Print addresses after aliasing.
759 printf (" aliased to\n");
766 * Put packet back for processing.
772 (struct sockaddr*) &addr,
775 if (wrote != bytes) {
777 if (errno == EMSGSIZE) {
779 if (direction == OUTPUT &&
781 SendNeedFragIcmp (icmpSock,
783 mip->ifMTU - mip->aliasOverhead);
785 else if (errno == EACCES && logIpfwDenied) {
787 sprintf (msgBuf, "failed to write packet back");
793 static void HandleRoutingInfo (int fd)
796 struct if_msghdr ifMsg;
798 * Get packet from socket.
800 bytes = read (fd, &ifMsg, sizeof ifMsg);
803 Warn ("read from routing socket failed");
807 if (ifMsg.ifm_version != RTM_VERSION) {
809 Warn ("unexpected packet read from routing socket");
814 printf ("Routing message %#x received.\n", ifMsg.ifm_type);
816 if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO)) {
817 LIST_FOREACH(mip, &root, list) {
819 if (ifMsg.ifm_index == mip->ifIndex) {
821 printf("Interface address/MTU has probably changed.\n");
822 mip->assignAliasAddr = 1;
828 static void PrintPacket (struct ip* ip)
830 printf ("%s", FormatPacket (ip));
833 static void SyslogPacket (struct ip* ip, int priority, const char *label)
835 syslog (priority, "%s %s", label, FormatPacket (ip));
838 static char* FormatPacket (struct ip* ip)
840 static char buf[256];
841 struct tcphdr* tcphdr;
842 struct udphdr* udphdr;
843 struct icmp* icmphdr;
847 strcpy (src, inet_ntoa (ip->ip_src));
848 strcpy (dst, inet_ntoa (ip->ip_dst));
852 tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2));
853 sprintf (buf, "[TCP] %s:%d -> %s:%d",
855 ntohs (tcphdr->th_sport),
857 ntohs (tcphdr->th_dport));
861 udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2));
862 sprintf (buf, "[UDP] %s:%d -> %s:%d",
864 ntohs (udphdr->uh_sport),
866 ntohs (udphdr->uh_dport));
870 icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2));
871 sprintf (buf, "[ICMP] %s -> %s %u(%u)",
879 sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst);
887 SetAliasAddressFromIfName(const char *ifn)
891 char *buf, *lim, *next;
892 struct if_msghdr *ifm;
893 struct ifa_msghdr *ifam;
894 struct sockaddr_dl *sdl;
895 struct sockaddr_in *sin;
900 mib[3] = AF_INET; /* Only IP addresses please */
901 mib[4] = NET_RT_IFLIST;
902 mib[5] = 0; /* ifIndex??? */
904 * Get interface data.
906 if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
907 err(1, "iflist-sysctl-estimate");
908 if ((buf = malloc(needed)) == NULL)
909 errx(1, "malloc failed");
910 if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1 && errno != ENOMEM)
911 err(1, "iflist-sysctl-get");
914 * Loop through interfaces until one with
915 * given name is found. This is done to
916 * find correct interface index for routing
917 * message processing.
922 ifm = (struct if_msghdr *)next;
923 next += ifm->ifm_msglen;
924 if (ifm->ifm_version != RTM_VERSION) {
926 warnx("routing message version %d "
927 "not understood", ifm->ifm_version);
930 if (ifm->ifm_type == RTM_IFINFO) {
931 sdl = (struct sockaddr_dl *)(ifm + 1);
932 if (strlen(ifn) == sdl->sdl_nlen &&
933 strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) {
934 mip->ifIndex = ifm->ifm_index;
935 mip->ifMTU = ifm->ifm_data.ifi_mtu;
941 errx(1, "unknown interface name %s", ifn);
943 * Get interface address.
947 ifam = (struct ifa_msghdr *)next;
948 next += ifam->ifam_msglen;
949 if (ifam->ifam_version != RTM_VERSION) {
951 warnx("routing message version %d "
952 "not understood", ifam->ifam_version);
955 if (ifam->ifam_type != RTM_NEWADDR)
957 if (ifam->ifam_addrs & RTA_IFA) {
959 char *cp = (char *)(ifam + 1);
961 for (i = 1; i < RTA_IFA; i <<= 1)
962 if (ifam->ifam_addrs & i)
963 cp += SA_SIZE((struct sockaddr *)cp);
964 if (((struct sockaddr *)cp)->sa_family == AF_INET) {
965 sin = (struct sockaddr_in *)cp;
971 warnx("%s: cannot get interface address", ifn);
976 LibAliasSetAddress(mla, sin->sin_addr);
977 syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes",
978 inet_ntoa(sin->sin_addr), mip->ifMTU);
985 void Quit (const char* msg)
991 void Warn (const char* msg)
994 syslog (LOG_ALERT, "%s (%m)", msg);
999 static void RefreshAddr (int sig __unused)
1001 LibAliasRefreshModules();
1002 if (mip != NULL && mip->ifName != NULL)
1003 mip->assignAliasAddr = 1;
1006 static void InitiateShutdown (int sig __unused)
1009 * Start timer to allow kernel gracefully
1010 * shutdown existing connections when system
1013 siginterrupt(SIGALRM, 1);
1014 signal (SIGALRM, Shutdown);
1015 ualarm(exitDelay*1000, 1000);
1018 static void Shutdown (int sig __unused)
1024 * Different options recognized by this program.
1065 * Option information structure (used by ParseOption).
1073 const char* parmDescription;
1074 const char* description;
1076 const char* shortName;
1080 * Table of known options.
1083 static struct OptionInfo optionTable[] = {
1086 PKT_ALIAS_UNREGISTERED_ONLY,
1089 "alias only unregistered addresses",
1090 "unregistered_only",
1102 PKT_ALIAS_PROXY_ONLY,
1113 "operate in reverse mode",
1118 PKT_ALIAS_DENY_INCOMING,
1121 "allow incoming connections",
1126 PKT_ALIAS_USE_SOCKETS,
1129 "use sockets to inhibit port conflict",
1134 PKT_ALIAS_SAME_PORTS,
1137 "try to keep original port numbers for connections",
1145 "verbose mode, dump packet information",
1153 "dynamic mode, automatically detect interface address changes",
1160 "number|service_name",
1161 "set port for incoming packets",
1168 "number|service_name",
1169 "set port for outgoing packets",
1176 "number|service_name",
1177 "set port (defaults to natd/divert)",
1184 "number|service_name",
1193 "address to use for aliasing",
1201 "address to use for incoming sessions",
1209 "take aliasing address from interface",
1216 "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
1218 "add transparent proxying / destination NAT",
1225 "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
1226 " [remote_addr[:remote_port_range]]",
1227 "redirect a port (or ports) for incoming traffic",
1234 "proto local_addr [public_addr] [remote_addr]",
1235 "redirect packets of a given proto",
1242 "local_addr[,...] public_addr",
1243 "define mapping between local and public addresses",
1251 "read options from configuration file",
1259 "enable logging of denied incoming packets",
1267 "name of syslog facility to use for logging",
1275 "punch holes in the firewall for incoming FTP/IRC DCC connections",
1283 "set the TCP port for use with the Skinny Station protocol",
1291 "log packets converted by natd, but denied by ipfw",
1299 "store PID in an alternate file",
1306 "name of aliasing engine instance",
1313 "delay in ms before daemon exit after signal",
1318 static void ParseOption (const char* option, const char* parms)
1321 struct OptionInfo* info;
1326 const char* strValue;
1327 struct in_addr addrValue;
1330 const CODE* fac_record = NULL;
1332 * Find option from table.
1334 max = sizeof (optionTable) / sizeof (struct OptionInfo);
1335 for (i = 0, info = optionTable; i < max; i++, info++) {
1337 if (!strcmp (info->name, option))
1340 if (info->shortName)
1341 if (!strcmp (info->shortName, option))
1347 warnx ("unknown option %s", option);
1358 switch (info->parm) {
1363 if (!strcmp (parms, "yes"))
1366 if (!strcmp (parms, "no"))
1369 errx (1, "%s needs yes/no parameter", option);
1374 errx (1, "%s needs service name or "
1375 "port number parameter",
1378 uNumValue = StrToPort (parms, "divert");
1383 numValue = strtol (parms, &end, 10);
1388 errx (1, "%s needs numeric parameter", option);
1394 errx (1, "%s needs parameter", option);
1399 errx (1, "%s does not take parameters", option);
1404 errx (1, "%s needs address/host parameter", option);
1406 StrToAddr (parms, &addrValue);
1410 switch (info->type) {
1411 case LibAliasOption:
1413 aliasValue = yesNoValue ? info->packetAliasOpt : 0;
1414 LibAliasSetMode (mla, aliasValue, info->packetAliasOpt);
1418 verbose = yesNoValue;
1422 dynamicMode = yesNoValue;
1426 mip->inPort = uNumValue;
1430 mip->outPort = uNumValue;
1434 mip->inOutPort = uNumValue;
1438 globalPort = uNumValue;
1442 memcpy (&mip->aliasAddr, &addrValue, sizeof (struct in_addr));
1446 LibAliasSetTarget(mla, addrValue);
1450 SetupPortRedirect (strValue);
1454 SetupProtoRedirect(strValue);
1457 case RedirectAddress:
1458 SetupAddressRedirect (strValue);
1462 LibAliasProxyRule (mla, strValue);
1469 mip->ifName = strdup (strValue);
1473 ReadConfigFile (strValue);
1477 mip->logDropped = yesNoValue;
1482 fac_record = facilitynames;
1483 while (fac_record->c_name != NULL) {
1485 if (!strcmp (fac_record->c_name, strValue)) {
1487 logFacility = fac_record->c_val;
1495 if(fac_record->c_name == NULL)
1496 errx(1, "Unknown log facility name: %s", strValue);
1501 SetupPunchFW(strValue);
1505 SetupSkinnyPort(strValue);
1509 logIpfwDenied = yesNoValue;
1513 pidName = strdup (strValue);
1516 NewInstance(strValue);
1519 if (numValue < 0 || numValue > MAX_EXIT_DELAY)
1520 errx(1, "Incorrect exit delay: %d", numValue);
1521 exitDelay = numValue;
1526 void ReadConfigFile (const char* fileName)
1534 file = fopen (fileName, "r");
1536 err(1, "cannot open config file %s", fileName);
1538 while ((buf = fgetln(file, &len)) != NULL) {
1539 if (buf[len - 1] == '\n')
1540 buf[len - 1] = '\0';
1542 errx(1, "config file format error: "
1543 "last line should end with newline");
1546 * Check for comments, strip off trailing spaces.
1548 if ((ptr = strchr(buf, '#')))
1550 for (ptr = buf; isspace(*ptr); ++ptr)
1554 for (p = strchr(buf, '\0'); isspace(*--p);)
1559 * Extract option name.
1562 while (*ptr && !isspace (*ptr))
1571 * Skip white space between name and parms.
1573 while (*ptr && isspace (*ptr))
1576 ParseOption (option, *ptr ? ptr : NULL);
1582 static void Usage(void)
1586 struct OptionInfo* info;
1588 fprintf (stderr, "Recognized options:\n\n");
1590 max = sizeof (optionTable) / sizeof (struct OptionInfo);
1591 for (i = 0, info = optionTable; i < max; i++, info++) {
1593 fprintf (stderr, "-%-20s %s\n", info->name,
1594 info->parmDescription);
1596 if (info->shortName)
1597 fprintf (stderr, "-%-20s %s\n", info->shortName,
1598 info->parmDescription);
1600 fprintf (stderr, " %s\n\n", info->description);
1606 void SetupPortRedirect (const char* parms)
1611 struct in_addr localAddr;
1612 struct in_addr publicAddr;
1613 struct in_addr remoteAddr;
1614 port_range portRange;
1615 u_short localPort = 0;
1616 u_short publicPort = 0;
1617 u_short remotePort = 0;
1618 u_short numLocalPorts = 0;
1619 u_short numPublicPorts = 0;
1620 u_short numRemotePorts = 0;
1625 struct alias_link *aliaslink = NULL;
1627 buf = strdup (parms);
1629 errx (1, "redirect_port: strdup() failed");
1633 protoName = strtok (buf, " \t");
1635 errx (1, "redirect_port: missing protocol");
1637 proto = StrToProto (protoName);
1639 * Extract local address.
1641 ptr = strtok (NULL, " \t");
1643 errx (1, "redirect_port: missing local address");
1645 separator = strchr(ptr, ',');
1646 if (separator) { /* LSNAT redirection syntax. */
1647 localAddr.s_addr = INADDR_NONE;
1652 if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 )
1653 errx (1, "redirect_port: invalid local port range");
1655 localPort = GETLOPORT(portRange);
1656 numLocalPorts = GETNUMPORTS(portRange);
1661 * Extract public port and optionally address.
1663 ptr = strtok (NULL, " \t");
1665 errx (1, "redirect_port: missing public port");
1667 separator = strchr (ptr, ':');
1669 if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 )
1670 errx (1, "redirect_port: invalid public port range");
1673 publicAddr.s_addr = INADDR_ANY;
1674 if (StrToPortRange (ptr, protoName, &portRange) != 0)
1675 errx (1, "redirect_port: invalid public port range");
1678 publicPort = GETLOPORT(portRange);
1679 numPublicPorts = GETNUMPORTS(portRange);
1682 * Extract remote address and optionally port.
1684 ptr = strtok (NULL, " \t");
1686 separator = strchr (ptr, ':');
1688 if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0)
1689 errx (1, "redirect_port: invalid remote port range");
1691 SETLOPORT(portRange, 0);
1692 SETNUMPORTS(portRange, 1);
1693 StrToAddr (ptr, &remoteAddr);
1697 SETLOPORT(portRange, 0);
1698 SETNUMPORTS(portRange, 1);
1699 remoteAddr.s_addr = INADDR_ANY;
1702 remotePort = GETLOPORT(portRange);
1703 numRemotePorts = GETNUMPORTS(portRange);
1706 * Make sure port ranges match up, then add the redirect ports.
1708 if (numLocalPorts != numPublicPorts)
1709 errx (1, "redirect_port: port ranges must be equal in size");
1711 /* Remote port range is allowed to be '0' which means all ports. */
1712 if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0))
1713 errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
1715 for (i = 0 ; i < numPublicPorts ; ++i) {
1716 /* If remotePort is all ports, set it to 0. */
1717 u_short remotePortCopy = remotePort + i;
1718 if (numRemotePorts == 1 && remotePort == 0)
1721 aliaslink = LibAliasRedirectPort (mla, localAddr,
1722 htons(localPort + i),
1724 htons(remotePortCopy),
1726 htons(publicPort + i),
1731 * Setup LSNAT server pool.
1733 if (serverPool != NULL && aliaslink != NULL) {
1734 ptr = strtok(serverPool, ",");
1735 while (ptr != NULL) {
1736 if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0)
1737 errx(1, "redirect_port: invalid local port range");
1739 localPort = GETLOPORT(portRange);
1740 if (GETNUMPORTS(portRange) != 1)
1741 errx(1, "redirect_port: local port must be single in this context");
1742 LibAliasAddServer(mla, aliaslink, localAddr, htons(localPort));
1743 ptr = strtok(NULL, ",");
1751 SetupProtoRedirect(const char* parms)
1755 struct in_addr localAddr;
1756 struct in_addr publicAddr;
1757 struct in_addr remoteAddr;
1760 struct protoent *protoent;
1762 buf = strdup (parms);
1764 errx (1, "redirect_port: strdup() failed");
1768 protoName = strtok(buf, " \t");
1770 errx(1, "redirect_proto: missing protocol");
1772 protoent = getprotobyname(protoName);
1773 if (protoent == NULL)
1774 errx(1, "redirect_proto: unknown protocol %s", protoName);
1776 proto = protoent->p_proto;
1778 * Extract local address.
1780 ptr = strtok(NULL, " \t");
1782 errx(1, "redirect_proto: missing local address");
1784 StrToAddr(ptr, &localAddr);
1786 * Extract optional public address.
1788 ptr = strtok(NULL, " \t");
1790 StrToAddr(ptr, &publicAddr);
1792 publicAddr.s_addr = INADDR_ANY;
1794 * Extract optional remote address.
1796 ptr = strtok(NULL, " \t");
1798 StrToAddr(ptr, &remoteAddr);
1800 remoteAddr.s_addr = INADDR_ANY;
1802 * Create aliasing link.
1804 (void)LibAliasRedirectProto(mla, localAddr, remoteAddr, publicAddr,
1810 void SetupAddressRedirect (const char* parms)
1815 struct in_addr localAddr;
1816 struct in_addr publicAddr;
1818 struct alias_link *aliaslink;
1820 buf = strdup (parms);
1822 errx (1, "redirect_port: strdup() failed");
1824 * Extract local address.
1826 ptr = strtok (buf, " \t");
1828 errx (1, "redirect_address: missing local address");
1830 separator = strchr(ptr, ',');
1831 if (separator) { /* LSNAT redirection syntax. */
1832 localAddr.s_addr = INADDR_NONE;
1835 StrToAddr (ptr, &localAddr);
1839 * Extract public address.
1841 ptr = strtok (NULL, " \t");
1843 errx (1, "redirect_address: missing public address");
1845 StrToAddr (ptr, &publicAddr);
1846 aliaslink = LibAliasRedirectAddr(mla, localAddr, publicAddr);
1849 * Setup LSNAT server pool.
1851 if (serverPool != NULL && aliaslink != NULL) {
1852 ptr = strtok(serverPool, ",");
1853 while (ptr != NULL) {
1854 StrToAddr(ptr, &localAddr);
1855 LibAliasAddServer(mla, aliaslink, localAddr, htons(~0));
1856 ptr = strtok(NULL, ",");
1863 void StrToAddr (const char* str, struct in_addr* addr)
1867 if (inet_aton (str, addr))
1870 hp = gethostbyname (str);
1872 errx (1, "unknown host %s", str);
1874 memcpy (addr, hp->h_addr, sizeof (struct in_addr));
1877 u_short StrToPort (const char* str, const char* proto)
1883 port = strtol (str, &end, 10);
1885 return htons (port);
1887 sp = getservbyname (str, proto);
1889 errx (1, "%s/%s: unknown service", str, proto);
1894 int StrToPortRange (const char* str, const char* proto, port_range *portRange)
1902 /* First see if this is a service, return corresponding port if so. */
1903 sp = getservbyname (str,proto);
1905 SETLOPORT(*portRange, ntohs(sp->s_port));
1906 SETNUMPORTS(*portRange, 1);
1910 /* Not a service, see if it's a single port or port range. */
1911 sep = strchr (str, '-');
1913 SETLOPORT(*portRange, strtol(str, &end, 10));
1916 SETNUMPORTS(*portRange, 1);
1920 /* Error in port range field. */
1921 errx (1, "%s/%s: unknown service", str, proto);
1924 /* Port range, get the values and sanity check. */
1925 sscanf (str, "%hu-%hu", &loPort, &hiPort);
1926 SETLOPORT(*portRange, loPort);
1927 SETNUMPORTS(*portRange, 0); /* Error by default */
1928 if (loPort <= hiPort)
1929 SETNUMPORTS(*portRange, hiPort - loPort + 1);
1931 if (GETNUMPORTS(*portRange) == 0)
1932 errx (1, "invalid port range %s", str);
1939 StrToProto (const char* str)
1941 if (!strcmp (str, "tcp"))
1944 if (!strcmp (str, "udp"))
1947 errx (1, "unknown protocol %s. Expected tcp or udp", str);
1951 StrToAddrAndPortRange (char* str, struct in_addr* addr, char* proto, port_range *portRange)
1955 ptr = strchr (str, ':');
1957 errx (1, "%s is missing port number", str);
1962 StrToAddr (str, addr);
1963 return StrToPortRange (ptr, proto, portRange);
1967 SetupPunchFW(const char *strValue)
1969 unsigned int base, num;
1971 if (sscanf(strValue, "%u:%u", &base, &num) != 2)
1972 errx(1, "punch_fw: basenumber:count parameter required");
1974 if (CheckIpfwRulenum(base + num - 1) == -1)
1975 errx(1, "punch_fw: basenumber:count parameter should fit "
1976 "the maximum allowed rule numbers");
1978 LibAliasSetFWBase(mla, base, num);
1979 (void)LibAliasSetMode(mla, PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);
1983 SetupSkinnyPort(const char *strValue)
1987 if (sscanf(strValue, "%u", &port) != 1)
1988 errx(1, "skinny_port: port parameter required");
1990 LibAliasSetSkinnyPort(mla, port);
1994 NewInstance(const char *name)
1996 struct instance *ip;
1998 LIST_FOREACH(ip, &root, list) {
1999 if (!strcmp(ip->name, name)) {
2006 ip = calloc(1, sizeof(*ip));
2007 ip->name = strdup(name);
2008 ip->la = LibAliasInit (ip->la);
2009 ip->assignAliasAddr = 0;
2015 ip->aliasAddr.s_addr = INADDR_NONE;
2017 ip->aliasOverhead = 12;
2018 LIST_INSERT_HEAD(&root, ip, list);
2024 CheckIpfwRulenum(unsigned int rnum)
2026 unsigned int default_rule;
2027 size_t len = sizeof(default_rule);
2029 if (sysctlbyname("net.inet.ip.fw.default_rule", &default_rule, &len,
2031 warn("Failed to get the default ipfw rule number, using "
2032 "default historical value 65535. The reason was");
2033 default_rule = 65535;
2035 if (rnum >= default_rule) {