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 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;
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} %08x", 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)
975 mip->assignAliasAddr = 1;
978 static void InitiateShutdown (int sig)
981 * Start timer to allow kernel gracefully
982 * shutdown existing connections when system
985 siginterrupt(SIGALRM, 1);
986 signal (SIGALRM, Shutdown);
990 static void Shutdown (int sig)
996 * Different options recognized by this program.
1036 * Option information structure (used by ParseOption).
1044 const char* parmDescription;
1045 const char* description;
1047 const char* shortName;
1051 * Table of known options.
1054 static struct OptionInfo optionTable[] = {
1057 PKT_ALIAS_UNREGISTERED_ONLY,
1060 "alias only unregistered addresses",
1061 "unregistered_only",
1073 PKT_ALIAS_PROXY_ONLY,
1084 "operate in reverse mode",
1089 PKT_ALIAS_DENY_INCOMING,
1092 "allow incoming connections",
1097 PKT_ALIAS_USE_SOCKETS,
1100 "use sockets to inhibit port conflict",
1105 PKT_ALIAS_SAME_PORTS,
1108 "try to keep original port numbers for connections",
1116 "verbose mode, dump packet information",
1124 "dynamic mode, automatically detect interface address changes",
1131 "number|service_name",
1132 "set port for incoming packets",
1139 "number|service_name",
1140 "set port for outgoing packets",
1147 "number|service_name",
1148 "set port (defaults to natd/divert)",
1155 "number|service_name",
1164 "address to use for aliasing",
1172 "address to use for incoming sessions",
1180 "take aliasing address from interface",
1187 "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
1189 "add transparent proxying / destination NAT",
1196 "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
1197 " [remote_addr[:remote_port_range]]",
1198 "redirect a port (or ports) for incoming traffic",
1205 "proto local_addr [public_addr] [remote_addr]",
1206 "redirect packets of a given proto",
1213 "local_addr[,...] public_addr",
1214 "define mapping between local and public addresses",
1222 "read options from configuration file",
1230 "enable logging of denied incoming packets",
1238 "name of syslog facility to use for logging",
1246 "punch holes in the firewall for incoming FTP/IRC DCC connections",
1254 "set the TCP port for use with the Skinny Station protocol",
1262 "log packets converted by natd, but denied by ipfw",
1270 "store PID in an alternate file",
1277 "name of aliasing engine instance",
1282 static void ParseOption (const char* option, const char* parms)
1285 struct OptionInfo* info;
1290 const char* strValue;
1291 struct in_addr addrValue;
1294 CODE* fac_record = NULL;
1296 * Find option from table.
1298 max = sizeof (optionTable) / sizeof (struct OptionInfo);
1299 for (i = 0, info = optionTable; i < max; i++, info++) {
1301 if (!strcmp (info->name, option))
1304 if (info->shortName)
1305 if (!strcmp (info->shortName, option))
1311 warnx ("unknown option %s", option);
1322 switch (info->parm) {
1327 if (!strcmp (parms, "yes"))
1330 if (!strcmp (parms, "no"))
1333 errx (1, "%s needs yes/no parameter", option);
1338 errx (1, "%s needs service name or "
1339 "port number parameter",
1342 uNumValue = StrToPort (parms, "divert");
1347 numValue = strtol (parms, &end, 10);
1352 errx (1, "%s needs numeric parameter", option);
1358 errx (1, "%s needs parameter", option);
1363 errx (1, "%s does not take parameters", option);
1368 errx (1, "%s needs address/host parameter", option);
1370 StrToAddr (parms, &addrValue);
1374 switch (info->type) {
1375 case LibAliasOption:
1377 aliasValue = yesNoValue ? info->packetAliasOpt : 0;
1378 LibAliasSetMode (mla, aliasValue, info->packetAliasOpt);
1382 verbose = yesNoValue;
1386 dynamicMode = yesNoValue;
1390 mip->inPort = uNumValue;
1394 mip->outPort = uNumValue;
1398 mip->inOutPort = uNumValue;
1402 globalPort = uNumValue;
1406 memcpy (&mip->aliasAddr, &addrValue, sizeof (struct in_addr));
1410 LibAliasSetTarget(mla, addrValue);
1414 SetupPortRedirect (strValue);
1418 SetupProtoRedirect(strValue);
1421 case RedirectAddress:
1422 SetupAddressRedirect (strValue);
1426 LibAliasProxyRule (mla, strValue);
1433 mip->ifName = strdup (strValue);
1437 ReadConfigFile (strValue);
1441 mip->logDropped = yesNoValue;
1446 fac_record = facilitynames;
1447 while (fac_record->c_name != NULL) {
1449 if (!strcmp (fac_record->c_name, strValue)) {
1451 logFacility = fac_record->c_val;
1459 if(fac_record->c_name == NULL)
1460 errx(1, "Unknown log facility name: %s", strValue);
1465 SetupPunchFW(strValue);
1469 SetupSkinnyPort(strValue);
1473 logIpfwDenied = yesNoValue;;
1477 pidName = strdup (strValue);
1480 NewInstance(strValue);
1485 void ReadConfigFile (const char* fileName)
1493 file = fopen (fileName, "r");
1495 err(1, "cannot open config file %s", fileName);
1497 while ((buf = fgetln(file, &len)) != NULL) {
1498 if (buf[len - 1] == '\n')
1499 buf[len - 1] = '\0';
1501 errx(1, "config file format error: "
1502 "last line should end with newline");
1505 * Check for comments, strip off trailing spaces.
1507 if ((ptr = strchr(buf, '#')))
1509 for (ptr = buf; isspace(*ptr); ++ptr)
1513 for (p = strchr(buf, '\0'); isspace(*--p);)
1518 * Extract option name.
1521 while (*ptr && !isspace (*ptr))
1530 * Skip white space between name and parms.
1532 while (*ptr && isspace (*ptr))
1535 ParseOption (option, *ptr ? ptr : NULL);
1541 static void Usage ()
1545 struct OptionInfo* info;
1547 fprintf (stderr, "Recognized options:\n\n");
1549 max = sizeof (optionTable) / sizeof (struct OptionInfo);
1550 for (i = 0, info = optionTable; i < max; i++, info++) {
1552 fprintf (stderr, "-%-20s %s\n", info->name,
1553 info->parmDescription);
1555 if (info->shortName)
1556 fprintf (stderr, "-%-20s %s\n", info->shortName,
1557 info->parmDescription);
1559 fprintf (stderr, " %s\n\n", info->description);
1565 void SetupPortRedirect (const char* parms)
1570 struct in_addr localAddr;
1571 struct in_addr publicAddr;
1572 struct in_addr remoteAddr;
1573 port_range portRange;
1574 u_short localPort = 0;
1575 u_short publicPort = 0;
1576 u_short remotePort = 0;
1577 u_short numLocalPorts = 0;
1578 u_short numPublicPorts = 0;
1579 u_short numRemotePorts = 0;
1584 struct alias_link *link = NULL;
1586 strlcpy (buf, parms, sizeof(buf));
1590 protoName = strtok (buf, " \t");
1592 errx (1, "redirect_port: missing protocol");
1594 proto = StrToProto (protoName);
1596 * Extract local address.
1598 ptr = strtok (NULL, " \t");
1600 errx (1, "redirect_port: missing local address");
1602 separator = strchr(ptr, ',');
1603 if (separator) { /* LSNAT redirection syntax. */
1604 localAddr.s_addr = INADDR_NONE;
1609 if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 )
1610 errx (1, "redirect_port: invalid local port range");
1612 localPort = GETLOPORT(portRange);
1613 numLocalPorts = GETNUMPORTS(portRange);
1618 * Extract public port and optionally address.
1620 ptr = strtok (NULL, " \t");
1622 errx (1, "redirect_port: missing public port");
1624 separator = strchr (ptr, ':');
1626 if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 )
1627 errx (1, "redirect_port: invalid public port range");
1630 publicAddr.s_addr = INADDR_ANY;
1631 if (StrToPortRange (ptr, protoName, &portRange) != 0)
1632 errx (1, "redirect_port: invalid public port range");
1635 publicPort = GETLOPORT(portRange);
1636 numPublicPorts = GETNUMPORTS(portRange);
1639 * Extract remote address and optionally port.
1641 ptr = strtok (NULL, " \t");
1643 separator = strchr (ptr, ':');
1645 if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0)
1646 errx (1, "redirect_port: invalid remote port range");
1648 SETLOPORT(portRange, 0);
1649 SETNUMPORTS(portRange, 1);
1650 StrToAddr (ptr, &remoteAddr);
1654 SETLOPORT(portRange, 0);
1655 SETNUMPORTS(portRange, 1);
1656 remoteAddr.s_addr = INADDR_ANY;
1659 remotePort = GETLOPORT(portRange);
1660 numRemotePorts = GETNUMPORTS(portRange);
1663 * Make sure port ranges match up, then add the redirect ports.
1665 if (numLocalPorts != numPublicPorts)
1666 errx (1, "redirect_port: port ranges must be equal in size");
1668 /* Remote port range is allowed to be '0' which means all ports. */
1669 if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0))
1670 errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
1672 for (i = 0 ; i < numPublicPorts ; ++i) {
1673 /* If remotePort is all ports, set it to 0. */
1674 u_short remotePortCopy = remotePort + i;
1675 if (numRemotePorts == 1 && remotePort == 0)
1678 link = LibAliasRedirectPort (mla, localAddr,
1679 htons(localPort + i),
1681 htons(remotePortCopy),
1683 htons(publicPort + i),
1688 * Setup LSNAT server pool.
1690 if (serverPool != NULL && link != NULL) {
1691 ptr = strtok(serverPool, ",");
1692 while (ptr != NULL) {
1693 if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0)
1694 errx(1, "redirect_port: invalid local port range");
1696 localPort = GETLOPORT(portRange);
1697 if (GETNUMPORTS(portRange) != 1)
1698 errx(1, "redirect_port: local port must be single in this context");
1699 LibAliasAddServer(mla, link, localAddr, htons(localPort));
1700 ptr = strtok(NULL, ",");
1706 SetupProtoRedirect(const char* parms)
1710 struct in_addr localAddr;
1711 struct in_addr publicAddr;
1712 struct in_addr remoteAddr;
1715 struct protoent *protoent;
1717 strlcpy (buf, parms, sizeof(buf));
1721 protoName = strtok(buf, " \t");
1723 errx(1, "redirect_proto: missing protocol");
1725 protoent = getprotobyname(protoName);
1726 if (protoent == NULL)
1727 errx(1, "redirect_proto: unknown protocol %s", protoName);
1729 proto = protoent->p_proto;
1731 * Extract local address.
1733 ptr = strtok(NULL, " \t");
1735 errx(1, "redirect_proto: missing local address");
1737 StrToAddr(ptr, &localAddr);
1739 * Extract optional public address.
1741 ptr = strtok(NULL, " \t");
1743 StrToAddr(ptr, &publicAddr);
1745 publicAddr.s_addr = INADDR_ANY;
1747 * Extract optional remote address.
1749 ptr = strtok(NULL, " \t");
1751 StrToAddr(ptr, &remoteAddr);
1753 remoteAddr.s_addr = INADDR_ANY;
1755 * Create aliasing link.
1757 (void)LibAliasRedirectProto(mla, localAddr, remoteAddr, publicAddr,
1761 void SetupAddressRedirect (const char* parms)
1766 struct in_addr localAddr;
1767 struct in_addr publicAddr;
1769 struct alias_link *link;
1771 strlcpy (buf, parms, sizeof(buf));
1773 * Extract local address.
1775 ptr = strtok (buf, " \t");
1777 errx (1, "redirect_address: missing local address");
1779 separator = strchr(ptr, ',');
1780 if (separator) { /* LSNAT redirection syntax. */
1781 localAddr.s_addr = INADDR_NONE;
1784 StrToAddr (ptr, &localAddr);
1788 * Extract public address.
1790 ptr = strtok (NULL, " \t");
1792 errx (1, "redirect_address: missing public address");
1794 StrToAddr (ptr, &publicAddr);
1795 link = LibAliasRedirectAddr(mla, localAddr, publicAddr);
1798 * Setup LSNAT server pool.
1800 if (serverPool != NULL && link != NULL) {
1801 ptr = strtok(serverPool, ",");
1802 while (ptr != NULL) {
1803 StrToAddr(ptr, &localAddr);
1804 LibAliasAddServer(mla, link, localAddr, htons(~0));
1805 ptr = strtok(NULL, ",");
1810 void StrToAddr (const char* str, struct in_addr* addr)
1814 if (inet_aton (str, addr))
1817 hp = gethostbyname (str);
1819 errx (1, "unknown host %s", str);
1821 memcpy (addr, hp->h_addr, sizeof (struct in_addr));
1824 u_short StrToPort (const char* str, const char* proto)
1830 port = strtol (str, &end, 10);
1832 return htons (port);
1834 sp = getservbyname (str, proto);
1836 errx (1, "%s/%s: unknown service", str, proto);
1841 int StrToPortRange (const char* str, const char* proto, port_range *portRange)
1849 /* First see if this is a service, return corresponding port if so. */
1850 sp = getservbyname (str,proto);
1852 SETLOPORT(*portRange, ntohs(sp->s_port));
1853 SETNUMPORTS(*portRange, 1);
1857 /* Not a service, see if it's a single port or port range. */
1858 sep = strchr (str, '-');
1860 SETLOPORT(*portRange, strtol(str, &end, 10));
1863 SETNUMPORTS(*portRange, 1);
1867 /* Error in port range field. */
1868 errx (1, "%s/%s: unknown service", str, proto);
1871 /* Port range, get the values and sanity check. */
1872 sscanf (str, "%hu-%hu", &loPort, &hiPort);
1873 SETLOPORT(*portRange, loPort);
1874 SETNUMPORTS(*portRange, 0); /* Error by default */
1875 if (loPort <= hiPort)
1876 SETNUMPORTS(*portRange, hiPort - loPort + 1);
1878 if (GETNUMPORTS(*portRange) == 0)
1879 errx (1, "invalid port range %s", str);
1885 int StrToProto (const char* str)
1887 if (!strcmp (str, "tcp"))
1890 if (!strcmp (str, "udp"))
1893 errx (1, "unknown protocol %s. Expected tcp or udp", str);
1896 int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange)
1900 ptr = strchr (str, ':');
1902 errx (1, "%s is missing port number", str);
1907 StrToAddr (str, addr);
1908 return StrToPortRange (ptr, proto, portRange);
1912 SetupPunchFW(const char *strValue)
1914 unsigned int base, num;
1916 if (sscanf(strValue, "%u:%u", &base, &num) != 2)
1917 errx(1, "punch_fw: basenumber:count parameter required");
1919 LibAliasSetFWBase(mla, base, num);
1920 (void)LibAliasSetMode(mla, PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);
1924 SetupSkinnyPort(const char *strValue)
1928 if (sscanf(strValue, "%u", &port) != 1)
1929 errx(1, "skinny_port: port parameter required");
1931 LibAliasSetSkinnyPort(mla, port);
1935 NewInstance(const char *name)
1937 struct instance *ip;
1939 LIST_FOREACH(ip, &root, list) {
1940 if (!strcmp(ip->name, name)) {
1947 ip = calloc(sizeof *ip, 1);
1948 ip->name = strdup(name);
1949 ip->la = LibAliasInit (ip->la);
1950 ip->assignAliasAddr = 0;
1956 ip->aliasAddr.s_addr = INADDR_NONE;
1958 ip->aliasOverhead = 12;
1959 LIST_INSERT_HEAD(&root, ip, list);