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>
12 * $FreeBSD: src/sbin/natd/natd.c,v 1.25.2.5 2002/02/01 09:18:32 ru Exp $
13 * $DragonFly: src/sbin/natd/natd.c,v 1.6 2004/12/18 21:43:39 swildner Exp $
18 #include <sys/param.h>
19 #include <sys/socket.h>
20 #include <sys/sysctl.h>
23 #include <netinet/in.h>
24 #include <netinet/in_systm.h>
25 #include <netinet/ip.h>
26 #include <netinet/tcp.h>
27 #include <netinet/udp.h>
28 #include <netinet/ip_icmp.h>
30 #include <net/if_dl.h>
31 #include <net/route.h>
32 #include <arpa/inet.h>
49 * Default values for input and output
50 * divert socket ports.
53 #define DEFAULT_SERVICE "natd"
56 * Definition of a port range, and macros to deal with values.
57 * FORMAT: HI 16-bits == first port in range, 0 == all ports.
58 * LO 16-bits == number of ports in range
59 * NOTES: - Port values are not stored in network byte order.
62 typedef u_long port_range;
64 #define GETLOPORT(x) ((x) >> 0x10)
65 #define GETNUMPORTS(x) ((x) & 0x0000ffff)
66 #define GETHIPORT(x) (GETLOPORT((x)) + GETNUMPORTS((x)))
68 /* Set y to be the low-port value in port_range variable x. */
69 #define SETLOPORT(x,y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
71 /* Set y to be the number of ports in port_range variable x. */
72 #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y))
75 * Function prototypes.
78 static void DoAliasing (int fd, int direction);
79 static void DaemonMode (void);
80 static void HandleRoutingInfo (int fd);
81 static void Usage (void);
82 static char* FormatPacket (struct ip*);
83 static void PrintPacket (struct ip*);
84 static void SyslogPacket (struct ip*, int priority, const char *label);
85 static void SetAliasAddressFromIfName (const char *ifName);
86 static void InitiateShutdown (int);
87 static void Shutdown (int);
88 static void RefreshAddr (int);
89 static void ParseOption (const char* option, const char* parms);
90 static void ReadConfigFile (const char* fileName);
91 static void SetupPortRedirect (const char* parms);
92 static void SetupProtoRedirect(const char* parms);
93 static void SetupAddressRedirect (const char* parms);
94 static void StrToAddr (const char* str, struct in_addr* addr);
95 static u_short StrToPort (const char* str, const char* proto);
96 static int StrToPortRange (const char* str, const char* proto, port_range *portRange);
97 static int StrToProto (const char* str);
98 static int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange);
99 static void ParseArgs (int argc, char** argv);
100 static void SetupPunchFW(const char *strValue);
107 static int background;
109 static int assignAliasAddr;
112 static u_short inPort;
113 static u_short outPort;
114 static u_short inOutPort;
115 static struct in_addr aliasAddr;
116 static int dynamicMode;
118 static int aliasOverhead;
120 static int dropIgnoredIncoming;
121 static int logDropped;
122 static int logFacility;
123 static int logIpfwDenied;
125 int main (int argc, char** argv)
131 struct sockaddr_in addr;
135 * Initialize packet aliasing software.
136 * Done already here to be able to alter option bits
137 * during command line and configuration file processing.
152 aliasAddr.s_addr = INADDR_NONE;
156 logFacility = LOG_DAEMON;
159 ParseArgs (argc, argv);
161 * Log ipfw(8) denied packets by default in verbose mode.
163 if (logIpfwDenied == -1)
164 logIpfwDenied = verbose;
166 * Open syslog channel.
168 openlog ("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0),
171 * Check that valid aliasing address has been given.
173 if (aliasAddr.s_addr == INADDR_NONE && ifName == NULL)
174 errx (1, "aliasing address not given");
176 if (aliasAddr.s_addr != INADDR_NONE && ifName != NULL)
177 errx (1, "both alias address and interface "
178 "name are not allowed");
180 * Check that valid port number is known.
182 if (inPort != 0 || outPort != 0)
183 if (inPort == 0 || outPort == 0)
184 errx (1, "both input and output ports are required");
186 if (inPort == 0 && outPort == 0 && inOutPort == 0)
187 ParseOption ("port", DEFAULT_SERVICE);
190 * Check if ignored packets should be dropped.
192 dropIgnoredIncoming = PacketAliasSetMode (0, 0);
193 dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING;
195 * Create divert sockets. Use only one socket if -p was specified
196 * on command line. Otherwise, create separate sockets for
197 * outgoing and incoming connnections.
201 divertInOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
202 if (divertInOut == -1)
203 Quit ("Unable to create divert socket.");
211 addr.sin_family = AF_INET;
212 addr.sin_addr.s_addr = INADDR_ANY;
213 addr.sin_port = inOutPort;
215 if (bind (divertInOut,
216 (struct sockaddr*) &addr,
218 Quit ("Unable to bind divert socket.");
222 divertIn = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
224 Quit ("Unable to create incoming divert socket.");
226 divertOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
228 Quit ("Unable to create outgoing divert socket.");
233 * Bind divert sockets.
236 addr.sin_family = AF_INET;
237 addr.sin_addr.s_addr = INADDR_ANY;
238 addr.sin_port = inPort;
241 (struct sockaddr*) &addr,
243 Quit ("Unable to bind incoming divert socket.");
245 addr.sin_family = AF_INET;
246 addr.sin_addr.s_addr = INADDR_ANY;
247 addr.sin_port = outPort;
250 (struct sockaddr*) &addr,
252 Quit ("Unable to bind outgoing divert socket.");
255 * Create routing socket if interface name specified and in dynamic mode.
261 routeSock = socket (PF_ROUTE, SOCK_RAW, 0);
263 Quit ("Unable to create routing info socket.");
268 SetAliasAddressFromIfName (ifName);
271 * Create socket for sending ICMP messages.
273 icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
275 Quit ("Unable to create ICMP socket.");
278 * And disable reads for the socket, otherwise it slowly fills
279 * up with received icmps which we do not use.
281 shutdown(icmpSock, SHUT_RD);
284 * Become a daemon unless verbose mode was requested.
289 * Catch signals to manage shutdown and
290 * refresh of interface address.
292 siginterrupt(SIGTERM, 1);
293 siginterrupt(SIGHUP, 1);
294 signal (SIGTERM, InitiateShutdown);
295 signal (SIGHUP, RefreshAddr);
297 * Set alias address if it has been given.
299 if (aliasAddr.s_addr != INADDR_NONE)
300 PacketAliasSetAddress (aliasAddr);
302 * We need largest descriptor number for select.
307 if (divertIn > fdMax)
310 if (divertOut > fdMax)
313 if (divertInOut > fdMax)
316 if (routeSock > fdMax)
321 if (divertInOut != -1 && !ifName) {
323 * When using only one socket, just call
324 * DoAliasing repeatedly to process packets.
326 DoAliasing (divertInOut, DONT_KNOW);
330 * Build read mask from socket descriptors to select.
334 * Check if new packets are available.
337 FD_SET (divertIn, &readMask);
340 FD_SET (divertOut, &readMask);
342 if (divertInOut != -1)
343 FD_SET (divertInOut, &readMask);
345 * Routing info is processed always.
348 FD_SET (routeSock, &readMask);
350 if (select (fdMax + 1,
359 Quit ("Select failed.");
363 if (FD_ISSET (divertIn, &readMask))
364 DoAliasing (divertIn, INPUT);
367 if (FD_ISSET (divertOut, &readMask))
368 DoAliasing (divertOut, OUTPUT);
370 if (divertInOut != -1)
371 if (FD_ISSET (divertInOut, &readMask))
372 DoAliasing (divertInOut, DONT_KNOW);
375 if (FD_ISSET (routeSock, &readMask))
376 HandleRoutingInfo (routeSock);
385 static void DaemonMode (void)
392 pidFile = fopen (PIDFILE, "w");
395 fprintf (pidFile, "%d\n", getpid ());
400 static void ParseArgs (int argc, char** argv)
405 int len; /* bounds checking */
407 for (arg = 1; arg < argc; arg++) {
412 warnx ("invalid option %s", opt);
419 while (arg < argc - 1) {
421 if (argv[arg + 1][0] == '-')
425 strncat (parmBuf, " ", sizeof(parmBuf) - (len + 1));
426 len += strlen(parmBuf + len);
430 strncat (parmBuf, argv[arg], sizeof(parmBuf) - (len + 1));
431 len += strlen(parmBuf + len);
435 ParseOption (opt + 1, (len ? parmBuf : NULL));
440 static void DoAliasing (int fd, int direction)
444 char buf[IP_MAXPACKET];
445 struct sockaddr_in addr;
452 if (assignAliasAddr) {
454 SetAliasAddressFromIfName (ifName);
458 * Get packet from socket.
460 addrSize = sizeof addr;
461 origBytes = recvfrom (fd,
465 (struct sockaddr*) &addr,
468 if (origBytes == -1) {
471 Warn ("read from divert socket failed");
476 * This is a IP packet.
478 ip = (struct ip*) buf;
479 if (direction == DONT_KNOW) {
480 if (addr.sin_addr.s_addr == INADDR_ANY)
488 * Print packet direction and protocol type.
490 printf (direction == OUTPUT ? "Out " : "In ");
506 printf ("[%d] ", ip->ip_p);
515 if (direction == OUTPUT) {
517 * Outgoing packets. Do aliasing.
519 PacketAliasOut (buf, IP_MAXPACKET);
526 status = PacketAliasIn (buf, IP_MAXPACKET);
527 if (status == PKT_ALIAS_IGNORED &&
528 dropIgnoredIncoming) {
531 printf (" dropped.\n");
534 SyslogPacket (ip, LOG_WARNING, "denied");
540 * Length might have changed during aliasing.
542 bytes = ntohs (ip->ip_len);
544 * Update alias overhead size for outgoing packets.
546 if (direction == OUTPUT &&
547 bytes - origBytes > aliasOverhead)
548 aliasOverhead = bytes - origBytes;
553 * Print addresses after aliasing.
555 printf (" aliased to\n");
562 * Put packet back for processing.
568 (struct sockaddr*) &addr,
571 if (wrote != bytes) {
573 if (errno == EMSGSIZE) {
575 if (direction == OUTPUT &&
577 SendNeedFragIcmp (icmpSock,
579 ifMTU - aliasOverhead);
581 else if (errno == EACCES && logIpfwDenied) {
583 sprintf (msgBuf, "failed to write packet back");
589 static void HandleRoutingInfo (int fd)
592 struct if_msghdr ifMsg;
594 * Get packet from socket.
596 bytes = read (fd, &ifMsg, sizeof ifMsg);
599 Warn ("read from routing socket failed");
603 if (ifMsg.ifm_version != RTM_VERSION) {
605 Warn ("unexpected packet read from routing socket");
610 printf ("Routing message %#x received.\n", ifMsg.ifm_type);
612 if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO) &&
613 ifMsg.ifm_index == ifIndex) {
615 printf("Interface address/MTU has probably changed.\n");
620 static void PrintPacket (struct ip* ip)
622 printf ("%s", FormatPacket (ip));
625 static void SyslogPacket (struct ip* ip, int priority, const char *label)
627 syslog (priority, "%s %s", label, FormatPacket (ip));
630 static char* FormatPacket (struct ip* ip)
632 static char buf[256];
633 struct tcphdr* tcphdr;
634 struct udphdr* udphdr;
635 struct icmp* icmphdr;
639 strcpy (src, inet_ntoa (ip->ip_src));
640 strcpy (dst, inet_ntoa (ip->ip_dst));
644 tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2));
645 sprintf (buf, "[TCP] %s:%d -> %s:%d",
647 ntohs (tcphdr->th_sport),
649 ntohs (tcphdr->th_dport));
653 udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2));
654 sprintf (buf, "[UDP] %s:%d -> %s:%d",
656 ntohs (udphdr->uh_sport),
658 ntohs (udphdr->uh_dport));
662 icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2));
663 sprintf (buf, "[ICMP] %s -> %s %u(%u)",
671 sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst);
679 SetAliasAddressFromIfName(const char *ifn)
683 char *buf, *lim, *next;
684 struct if_msghdr *ifm;
685 struct ifa_msghdr *ifam;
686 struct sockaddr_dl *sdl;
687 struct sockaddr_in *sin;
692 mib[3] = AF_INET; /* Only IP addresses please */
693 mib[4] = NET_RT_IFLIST;
694 mib[5] = 0; /* ifIndex??? */
696 * Get interface data.
698 if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
699 err(1, "iflist-sysctl-estimate");
700 if ((buf = malloc(needed)) == NULL)
701 errx(1, "malloc failed");
702 if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
703 err(1, "iflist-sysctl-get");
706 * Loop through interfaces until one with
707 * given name is found. This is done to
708 * find correct interface index for routing
709 * message processing.
714 ifm = (struct if_msghdr *)next;
715 next += ifm->ifm_msglen;
716 if (ifm->ifm_version != RTM_VERSION) {
718 warnx("routing message version %d "
719 "not understood", ifm->ifm_version);
722 if (ifm->ifm_type == RTM_IFINFO) {
723 sdl = (struct sockaddr_dl *)(ifm + 1);
724 if (strlen(ifn) == sdl->sdl_nlen &&
725 strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) {
726 ifIndex = ifm->ifm_index;
727 ifMTU = ifm->ifm_data.ifi_mtu;
733 errx(1, "unknown interface name %s", ifn);
735 * Get interface address.
739 ifam = (struct ifa_msghdr *)next;
740 next += ifam->ifam_msglen;
741 if (ifam->ifam_version != RTM_VERSION) {
743 warnx("routing message version %d "
744 "not understood", ifam->ifam_version);
747 if (ifam->ifam_type != RTM_NEWADDR)
749 if (ifam->ifam_addrs & RTA_IFA) {
751 char *cp = (char *)(ifam + 1);
754 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
755 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
757 for (i = 1; i < RTA_IFA; i <<= 1)
758 if (ifam->ifam_addrs & i)
759 ADVANCE(cp, (struct sockaddr *)cp);
760 if (((struct sockaddr *)cp)->sa_family == AF_INET) {
761 sin = (struct sockaddr_in *)cp;
767 errx(1, "%s: cannot get interface address", ifn);
769 PacketAliasSetAddress(sin->sin_addr);
770 syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes",
771 inet_ntoa(sin->sin_addr), ifMTU);
776 void Quit (const char* msg)
782 void Warn (const char* msg)
785 syslog (LOG_ALERT, "%s (%m)", msg);
790 static void RefreshAddr (int sig)
796 static void InitiateShutdown (int sig)
799 * Start timer to allow kernel gracefully
800 * shutdown existing connections when system
803 siginterrupt(SIGALRM, 1);
804 signal (SIGALRM, Shutdown);
808 static void Shutdown (int sig)
814 * Different options recognized by this program.
850 * Option information structure (used by ParseOption).
858 const char* parmDescription;
859 const char* description;
861 const char* shortName;
865 * Table of known options.
868 static struct OptionInfo optionTable[] = {
871 PKT_ALIAS_UNREGISTERED_ONLY,
874 "alias only unregistered addresses",
887 PKT_ALIAS_PROXY_ONLY,
898 "operate in reverse mode",
903 PKT_ALIAS_DENY_INCOMING,
906 "allow incoming connections",
911 PKT_ALIAS_USE_SOCKETS,
914 "use sockets to inhibit port conflict",
919 PKT_ALIAS_SAME_PORTS,
922 "try to keep original port numbers for connections",
930 "verbose mode, dump packet information",
938 "dynamic mode, automatically detect interface address changes",
945 "number|service_name",
946 "set port for incoming packets",
953 "number|service_name",
954 "set port for outgoing packets",
961 "number|service_name",
962 "set port (defaults to natd/divert)",
970 "address to use for aliasing",
978 "address to use for incoming sessions",
986 "take aliasing address from interface",
993 "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
995 "add transparent proxying / destination NAT",
1002 "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
1003 " [remote_addr[:remote_port_range]]",
1004 "redirect a port (or ports) for incoming traffic",
1011 "proto local_addr [public_addr] [remote_addr]",
1012 "redirect packets of a given proto",
1019 "local_addr[,...] public_addr",
1020 "define mapping between local and public addresses",
1028 "read options from configuration file",
1036 "enable logging of denied incoming packets",
1044 "name of syslog facility to use for logging",
1052 "punch holes in the firewall for incoming FTP/IRC DCC connections",
1060 "log packets converted by natd, but denied by ipfw",
1065 static void ParseOption (const char* option, const char* parms)
1068 struct OptionInfo* info;
1073 const char* strValue;
1074 struct in_addr addrValue;
1077 CODE* fac_record = NULL;
1079 * Find option from table.
1081 max = sizeof (optionTable) / sizeof (struct OptionInfo);
1082 for (i = 0, info = optionTable; i < max; i++, info++) {
1084 if (!strcmp (info->name, option))
1087 if (info->shortName)
1088 if (!strcmp (info->shortName, option))
1094 warnx ("unknown option %s", option);
1105 switch (info->parm) {
1110 if (!strcmp (parms, "yes"))
1113 if (!strcmp (parms, "no"))
1116 errx (1, "%s needs yes/no parameter", option);
1121 errx (1, "%s needs service name or "
1122 "port number parameter",
1125 uNumValue = StrToPort (parms, "divert");
1130 numValue = strtol (parms, &end, 10);
1135 errx (1, "%s needs numeric parameter", option);
1141 errx (1, "%s needs parameter", option);
1146 errx (1, "%s does not take parameters", option);
1151 errx (1, "%s needs address/host parameter", option);
1153 StrToAddr (parms, &addrValue);
1157 switch (info->type) {
1158 case PacketAliasOption:
1160 aliasValue = yesNoValue ? info->packetAliasOpt : 0;
1161 PacketAliasSetMode (aliasValue, info->packetAliasOpt);
1165 verbose = yesNoValue;
1169 dynamicMode = yesNoValue;
1177 outPort = uNumValue;
1181 inOutPort = uNumValue;
1185 memcpy (&aliasAddr, &addrValue, sizeof (struct in_addr));
1189 PacketAliasSetTarget(addrValue);
1193 SetupPortRedirect (strValue);
1197 SetupProtoRedirect(strValue);
1200 case RedirectAddress:
1201 SetupAddressRedirect (strValue);
1205 PacketAliasProxyRule (strValue);
1212 ifName = strdup (strValue);
1216 ReadConfigFile (strValue);
1220 logDropped = yesNoValue;
1225 fac_record = facilitynames;
1226 while (fac_record->c_name != NULL) {
1228 if (!strcmp (fac_record->c_name, strValue)) {
1230 logFacility = fac_record->c_val;
1238 if(fac_record->c_name == NULL)
1239 errx(1, "Unknown log facility name: %s", strValue);
1244 SetupPunchFW(strValue);
1248 logIpfwDenied = yesNoValue;;
1253 void ReadConfigFile (const char* fileName)
1261 file = fopen (fileName, "r");
1263 err(1, "cannot open config file %s", fileName);
1265 while ((buf = fgetln(file, &len)) != NULL) {
1266 if (buf[len - 1] == '\n')
1267 buf[len - 1] = '\0';
1269 errx(1, "config file format error: "
1270 "last line should end with newline");
1273 * Check for comments, strip off trailing spaces.
1275 if ((ptr = strchr(buf, '#')))
1277 for (ptr = buf; isspace(*ptr); ++ptr)
1281 for (p = strchr(buf, '\0'); isspace(*--p);)
1286 * Extract option name.
1289 while (*ptr && !isspace (*ptr))
1298 * Skip white space between name and parms.
1300 while (*ptr && isspace (*ptr))
1303 ParseOption (option, *ptr ? ptr : NULL);
1309 static void Usage (void)
1313 struct OptionInfo* info;
1315 fprintf (stderr, "Recognized options:\n\n");
1317 max = sizeof (optionTable) / sizeof (struct OptionInfo);
1318 for (i = 0, info = optionTable; i < max; i++, info++) {
1320 fprintf (stderr, "-%-20s %s\n", info->name,
1321 info->parmDescription);
1323 if (info->shortName)
1324 fprintf (stderr, "-%-20s %s\n", info->shortName,
1325 info->parmDescription);
1327 fprintf (stderr, " %s\n\n", info->description);
1333 void SetupPortRedirect (const char* parms)
1338 struct in_addr localAddr;
1339 struct in_addr publicAddr;
1340 struct in_addr remoteAddr;
1341 port_range portRange;
1342 u_short localPort = 0;
1343 u_short publicPort = 0;
1344 u_short remotePort = 0;
1345 u_short numLocalPorts = 0;
1346 u_short numPublicPorts = 0;
1347 u_short numRemotePorts = 0;
1352 struct alias_link *link = NULL;
1354 strcpy (buf, parms);
1358 protoName = strtok (buf, " \t");
1360 errx (1, "redirect_port: missing protocol");
1362 proto = StrToProto (protoName);
1364 * Extract local address.
1366 ptr = strtok (NULL, " \t");
1368 errx (1, "redirect_port: missing local address");
1370 separator = strchr(ptr, ',');
1371 if (separator) { /* LSNAT redirection syntax. */
1372 localAddr.s_addr = INADDR_NONE;
1377 if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 )
1378 errx (1, "redirect_port: invalid local port range");
1380 localPort = GETLOPORT(portRange);
1381 numLocalPorts = GETNUMPORTS(portRange);
1386 * Extract public port and optionally address.
1388 ptr = strtok (NULL, " \t");
1390 errx (1, "redirect_port: missing public port");
1392 separator = strchr (ptr, ':');
1394 if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 )
1395 errx (1, "redirect_port: invalid public port range");
1398 publicAddr.s_addr = INADDR_ANY;
1399 if (StrToPortRange (ptr, protoName, &portRange) != 0)
1400 errx (1, "redirect_port: invalid public port range");
1403 publicPort = GETLOPORT(portRange);
1404 numPublicPorts = GETNUMPORTS(portRange);
1407 * Extract remote address and optionally port.
1409 ptr = strtok (NULL, " \t");
1411 separator = strchr (ptr, ':');
1413 if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0)
1414 errx (1, "redirect_port: invalid remote port range");
1416 SETLOPORT(portRange, 0);
1417 SETNUMPORTS(portRange, 1);
1418 StrToAddr (ptr, &remoteAddr);
1422 SETLOPORT(portRange, 0);
1423 SETNUMPORTS(portRange, 1);
1424 remoteAddr.s_addr = INADDR_ANY;
1427 remotePort = GETLOPORT(portRange);
1428 numRemotePorts = GETNUMPORTS(portRange);
1431 * Make sure port ranges match up, then add the redirect ports.
1433 if (numLocalPorts != numPublicPorts)
1434 errx (1, "redirect_port: port ranges must be equal in size");
1436 /* Remote port range is allowed to be '0' which means all ports. */
1437 if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0))
1438 errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
1440 for (i = 0 ; i < numPublicPorts ; ++i) {
1441 /* If remotePort is all ports, set it to 0. */
1442 u_short remotePortCopy = remotePort + i;
1443 if (numRemotePorts == 1 && remotePort == 0)
1446 link = PacketAliasRedirectPort (localAddr,
1447 htons(localPort + i),
1449 htons(remotePortCopy),
1451 htons(publicPort + i),
1456 * Setup LSNAT server pool.
1458 if (serverPool != NULL && link != NULL) {
1459 ptr = strtok(serverPool, ",");
1460 while (ptr != NULL) {
1461 if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0)
1462 errx(1, "redirect_port: invalid local port range");
1464 localPort = GETLOPORT(portRange);
1465 if (GETNUMPORTS(portRange) != 1)
1466 errx(1, "redirect_port: local port must be single in this context");
1467 PacketAliasAddServer(link, localAddr, htons(localPort));
1468 ptr = strtok(NULL, ",");
1474 SetupProtoRedirect(const char* parms)
1478 struct in_addr localAddr;
1479 struct in_addr publicAddr;
1480 struct in_addr remoteAddr;
1483 struct protoent *protoent;
1485 strcpy (buf, parms);
1489 protoName = strtok(buf, " \t");
1491 errx(1, "redirect_proto: missing protocol");
1493 protoent = getprotobyname(protoName);
1494 if (protoent == NULL)
1495 errx(1, "redirect_proto: unknown protocol %s", protoName);
1497 proto = protoent->p_proto;
1499 * Extract local address.
1501 ptr = strtok(NULL, " \t");
1503 errx(1, "redirect_proto: missing local address");
1505 StrToAddr(ptr, &localAddr);
1507 * Extract optional public address.
1509 ptr = strtok(NULL, " \t");
1511 StrToAddr(ptr, &publicAddr);
1513 publicAddr.s_addr = INADDR_ANY;
1515 * Extract optional remote address.
1517 ptr = strtok(NULL, " \t");
1519 StrToAddr(ptr, &remoteAddr);
1521 remoteAddr.s_addr = INADDR_ANY;
1523 * Create aliasing link.
1525 PacketAliasRedirectProto(localAddr, remoteAddr, publicAddr, proto);
1528 void SetupAddressRedirect (const char* parms)
1533 struct in_addr localAddr;
1534 struct in_addr publicAddr;
1536 struct alias_link *link;
1538 strcpy (buf, parms);
1540 * Extract local address.
1542 ptr = strtok (buf, " \t");
1544 errx (1, "redirect_address: missing local address");
1546 separator = strchr(ptr, ',');
1547 if (separator) { /* LSNAT redirection syntax. */
1548 localAddr.s_addr = INADDR_NONE;
1551 StrToAddr (ptr, &localAddr);
1555 * Extract public address.
1557 ptr = strtok (NULL, " \t");
1559 errx (1, "redirect_address: missing public address");
1561 StrToAddr (ptr, &publicAddr);
1562 link = PacketAliasRedirectAddr(localAddr, publicAddr);
1565 * Setup LSNAT server pool.
1567 if (serverPool != NULL && link != NULL) {
1568 ptr = strtok(serverPool, ",");
1569 while (ptr != NULL) {
1570 StrToAddr(ptr, &localAddr);
1571 PacketAliasAddServer(link, localAddr, htons(~0));
1572 ptr = strtok(NULL, ",");
1577 void StrToAddr (const char* str, struct in_addr* addr)
1581 if (inet_aton (str, addr))
1584 hp = gethostbyname (str);
1586 errx (1, "unknown host %s", str);
1588 memcpy (addr, hp->h_addr, sizeof (struct in_addr));
1591 u_short StrToPort (const char* str, const char* proto)
1597 port = strtol (str, &end, 10);
1599 return htons (port);
1601 sp = getservbyname (str, proto);
1603 errx (1, "unknown service %s/%s", str, proto);
1608 int StrToPortRange (const char* str, const char* proto, port_range *portRange)
1616 /* First see if this is a service, return corresponding port if so. */
1617 sp = getservbyname (str,proto);
1619 SETLOPORT(*portRange, ntohs(sp->s_port));
1620 SETNUMPORTS(*portRange, 1);
1624 /* Not a service, see if it's a single port or port range. */
1625 sep = strchr (str, '-');
1627 SETLOPORT(*portRange, strtol(str, &end, 10));
1630 SETNUMPORTS(*portRange, 1);
1634 /* Error in port range field. */
1635 errx (1, "unknown service %s/%s", str, proto);
1638 /* Port range, get the values and sanity check. */
1639 sscanf (str, "%hu-%hu", &loPort, &hiPort);
1640 SETLOPORT(*portRange, loPort);
1641 SETNUMPORTS(*portRange, 0); /* Error by default */
1642 if (loPort <= hiPort)
1643 SETNUMPORTS(*portRange, hiPort - loPort + 1);
1645 if (GETNUMPORTS(*portRange) == 0)
1646 errx (1, "invalid port range %s", str);
1652 int StrToProto (const char* str)
1654 if (!strcmp (str, "tcp"))
1657 if (!strcmp (str, "udp"))
1660 errx (1, "unknown protocol %s. Expected tcp or udp", str);
1663 int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange)
1667 ptr = strchr (str, ':');
1669 errx (1, "%s is missing port number", str);
1674 StrToAddr (str, addr);
1675 return StrToPortRange (ptr, proto, portRange);
1679 SetupPunchFW(const char *strValue)
1681 unsigned int base, num;
1683 if (sscanf(strValue, "%u:%u", &base, &num) != 2)
1684 errx(1, "punch_fw: basenumber:count parameter required");
1686 PacketAliasSetFWBase(base, num);
1687 PacketAliasSetMode(PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);