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.3 2003/09/28 14:39:20 hmp Exp $
18 #include <sys/types.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 <machine/in_cksum.h>
27 #include <netinet/tcp.h>
28 #include <netinet/udp.h>
29 #include <netinet/ip_icmp.h>
31 #include <net/if_dl.h>
32 #include <net/route.h>
33 #include <arpa/inet.h>
50 * Default values for input and output
51 * divert socket ports.
54 #define DEFAULT_SERVICE "natd"
57 * Definition of a port range, and macros to deal with values.
58 * FORMAT: HI 16-bits == first port in range, 0 == all ports.
59 * LO 16-bits == number of ports in range
60 * NOTES: - Port values are not stored in network byte order.
63 typedef u_long port_range;
65 #define GETLOPORT(x) ((x) >> 0x10)
66 #define GETNUMPORTS(x) ((x) & 0x0000ffff)
67 #define GETHIPORT(x) (GETLOPORT((x)) + GETNUMPORTS((x)))
69 /* Set y to be the low-port value in port_range variable x. */
70 #define SETLOPORT(x,y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
72 /* Set y to be the number of ports in port_range variable x. */
73 #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y))
76 * Function prototypes.
79 static void DoAliasing (int fd, int direction);
80 static void DaemonMode (void);
81 static void HandleRoutingInfo (int fd);
82 static void Usage (void);
83 static char* FormatPacket (struct ip*);
84 static void PrintPacket (struct ip*);
85 static void SyslogPacket (struct ip*, int priority, const char *label);
86 static void SetAliasAddressFromIfName (const char *ifName);
87 static void InitiateShutdown (int);
88 static void Shutdown (int);
89 static void RefreshAddr (int);
90 static void ParseOption (const char* option, const char* parms);
91 static void ReadConfigFile (const char* fileName);
92 static void SetupPortRedirect (const char* parms);
93 static void SetupProtoRedirect(const char* parms);
94 static void SetupAddressRedirect (const char* parms);
95 static void StrToAddr (const char* str, struct in_addr* addr);
96 static u_short StrToPort (const char* str, const char* proto);
97 static int StrToPortRange (const char* str, const char* proto, port_range *portRange);
98 static int StrToProto (const char* str);
99 static int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange);
100 static void ParseArgs (int argc, char** argv);
101 static void SetupPunchFW(const char *strValue);
108 static int background;
110 static int assignAliasAddr;
113 static u_short inPort;
114 static u_short outPort;
115 static u_short inOutPort;
116 static struct in_addr aliasAddr;
117 static int dynamicMode;
119 static int aliasOverhead;
121 static int dropIgnoredIncoming;
122 static int logDropped;
123 static int logFacility;
124 static int logIpfwDenied;
126 int main (int argc, char** argv)
132 struct sockaddr_in addr;
136 * Initialize packet aliasing software.
137 * Done already here to be able to alter option bits
138 * during command line and configuration file processing.
153 aliasAddr.s_addr = INADDR_NONE;
157 logFacility = LOG_DAEMON;
160 ParseArgs (argc, argv);
162 * Log ipfw(8) denied packets by default in verbose mode.
164 if (logIpfwDenied == -1)
165 logIpfwDenied = verbose;
167 * Open syslog channel.
169 openlog ("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0),
172 * Check that valid aliasing address has been given.
174 if (aliasAddr.s_addr == INADDR_NONE && ifName == NULL)
175 errx (1, "aliasing address not given");
177 if (aliasAddr.s_addr != INADDR_NONE && ifName != NULL)
178 errx (1, "both alias address and interface "
179 "name are not allowed");
181 * Check that valid port number is known.
183 if (inPort != 0 || outPort != 0)
184 if (inPort == 0 || outPort == 0)
185 errx (1, "both input and output ports are required");
187 if (inPort == 0 && outPort == 0 && inOutPort == 0)
188 ParseOption ("port", DEFAULT_SERVICE);
191 * Check if ignored packets should be dropped.
193 dropIgnoredIncoming = PacketAliasSetMode (0, 0);
194 dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING;
196 * Create divert sockets. Use only one socket if -p was specified
197 * on command line. Otherwise, create separate sockets for
198 * outgoing and incoming connnections.
202 divertInOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
203 if (divertInOut == -1)
204 Quit ("Unable to create divert socket.");
212 addr.sin_family = AF_INET;
213 addr.sin_addr.s_addr = INADDR_ANY;
214 addr.sin_port = inOutPort;
216 if (bind (divertInOut,
217 (struct sockaddr*) &addr,
219 Quit ("Unable to bind divert socket.");
223 divertIn = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
225 Quit ("Unable to create incoming divert socket.");
227 divertOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
229 Quit ("Unable to create outgoing divert socket.");
234 * Bind divert sockets.
237 addr.sin_family = AF_INET;
238 addr.sin_addr.s_addr = INADDR_ANY;
239 addr.sin_port = inPort;
242 (struct sockaddr*) &addr,
244 Quit ("Unable to bind incoming divert socket.");
246 addr.sin_family = AF_INET;
247 addr.sin_addr.s_addr = INADDR_ANY;
248 addr.sin_port = outPort;
251 (struct sockaddr*) &addr,
253 Quit ("Unable to bind outgoing divert socket.");
256 * Create routing socket if interface name specified and in dynamic mode.
262 routeSock = socket (PF_ROUTE, SOCK_RAW, 0);
264 Quit ("Unable to create routing info socket.");
269 SetAliasAddressFromIfName (ifName);
272 * Create socket for sending ICMP messages.
274 icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
276 Quit ("Unable to create ICMP socket.");
279 * And disable reads for the socket, otherwise it slowly fills
280 * up with received icmps which we do not use.
282 shutdown(icmpSock, SHUT_RD);
285 * Become a daemon unless verbose mode was requested.
290 * Catch signals to manage shutdown and
291 * refresh of interface address.
293 siginterrupt(SIGTERM, 1);
294 siginterrupt(SIGHUP, 1);
295 signal (SIGTERM, InitiateShutdown);
296 signal (SIGHUP, RefreshAddr);
298 * Set alias address if it has been given.
300 if (aliasAddr.s_addr != INADDR_NONE)
301 PacketAliasSetAddress (aliasAddr);
303 * We need largest descriptor number for select.
308 if (divertIn > fdMax)
311 if (divertOut > fdMax)
314 if (divertInOut > fdMax)
317 if (routeSock > fdMax)
322 if (divertInOut != -1 && !ifName) {
324 * When using only one socket, just call
325 * DoAliasing repeatedly to process packets.
327 DoAliasing (divertInOut, DONT_KNOW);
331 * Build read mask from socket descriptors to select.
335 * Check if new packets are available.
338 FD_SET (divertIn, &readMask);
341 FD_SET (divertOut, &readMask);
343 if (divertInOut != -1)
344 FD_SET (divertInOut, &readMask);
346 * Routing info is processed always.
349 FD_SET (routeSock, &readMask);
351 if (select (fdMax + 1,
360 Quit ("Select failed.");
364 if (FD_ISSET (divertIn, &readMask))
365 DoAliasing (divertIn, INPUT);
368 if (FD_ISSET (divertOut, &readMask))
369 DoAliasing (divertOut, OUTPUT);
371 if (divertInOut != -1)
372 if (FD_ISSET (divertInOut, &readMask))
373 DoAliasing (divertInOut, DONT_KNOW);
376 if (FD_ISSET (routeSock, &readMask))
377 HandleRoutingInfo (routeSock);
386 static void DaemonMode (void)
393 pidFile = fopen (PIDFILE, "w");
396 fprintf (pidFile, "%d\n", getpid ());
401 static void ParseArgs (int argc, char** argv)
406 int len; /* bounds checking */
408 for (arg = 1; arg < argc; arg++) {
413 warnx ("invalid option %s", opt);
420 while (arg < argc - 1) {
422 if (argv[arg + 1][0] == '-')
426 strncat (parmBuf, " ", sizeof(parmBuf) - (len + 1));
427 len += strlen(parmBuf + len);
431 strncat (parmBuf, argv[arg], sizeof(parmBuf) - (len + 1));
432 len += strlen(parmBuf + len);
436 ParseOption (opt + 1, (len ? parmBuf : NULL));
441 static void DoAliasing (int fd, int direction)
445 char buf[IP_MAXPACKET];
446 struct sockaddr_in addr;
453 if (assignAliasAddr) {
455 SetAliasAddressFromIfName (ifName);
459 * Get packet from socket.
461 addrSize = sizeof addr;
462 origBytes = recvfrom (fd,
466 (struct sockaddr*) &addr,
469 if (origBytes == -1) {
472 Warn ("read from divert socket failed");
477 * This is a IP packet.
479 ip = (struct ip*) buf;
480 if (direction == DONT_KNOW) {
481 if (addr.sin_addr.s_addr == INADDR_ANY)
489 * Print packet direction and protocol type.
491 printf (direction == OUTPUT ? "Out " : "In ");
507 printf ("[%d] ", ip->ip_p);
516 if (direction == OUTPUT) {
518 * Outgoing packets. Do aliasing.
520 PacketAliasOut (buf, IP_MAXPACKET);
527 status = PacketAliasIn (buf, IP_MAXPACKET);
528 if (status == PKT_ALIAS_IGNORED &&
529 dropIgnoredIncoming) {
532 printf (" dropped.\n");
535 SyslogPacket (ip, LOG_WARNING, "denied");
541 * Length might have changed during aliasing.
543 bytes = ntohs (ip->ip_len);
545 * Update alias overhead size for outgoing packets.
547 if (direction == OUTPUT &&
548 bytes - origBytes > aliasOverhead)
549 aliasOverhead = bytes - origBytes;
554 * Print addresses after aliasing.
556 printf (" aliased to\n");
563 * Put packet back for processing.
569 (struct sockaddr*) &addr,
572 if (wrote != bytes) {
574 if (errno == EMSGSIZE) {
576 if (direction == OUTPUT &&
578 SendNeedFragIcmp (icmpSock,
580 ifMTU - aliasOverhead);
582 else if (errno == EACCES && logIpfwDenied) {
584 sprintf (msgBuf, "failed to write packet back");
590 static void HandleRoutingInfo (int fd)
593 struct if_msghdr ifMsg;
595 * Get packet from socket.
597 bytes = read (fd, &ifMsg, sizeof ifMsg);
600 Warn ("read from routing socket failed");
604 if (ifMsg.ifm_version != RTM_VERSION) {
606 Warn ("unexpected packet read from routing socket");
611 printf ("Routing message %#x received.\n", ifMsg.ifm_type);
613 if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO) &&
614 ifMsg.ifm_index == ifIndex) {
616 printf("Interface address/MTU has probably changed.\n");
621 static void PrintPacket (struct ip* ip)
623 printf ("%s", FormatPacket (ip));
626 static void SyslogPacket (struct ip* ip, int priority, const char *label)
628 syslog (priority, "%s %s", label, FormatPacket (ip));
631 static char* FormatPacket (struct ip* ip)
633 static char buf[256];
634 struct tcphdr* tcphdr;
635 struct udphdr* udphdr;
636 struct icmp* icmphdr;
640 strcpy (src, inet_ntoa (ip->ip_src));
641 strcpy (dst, inet_ntoa (ip->ip_dst));
645 tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2));
646 sprintf (buf, "[TCP] %s:%d -> %s:%d",
648 ntohs (tcphdr->th_sport),
650 ntohs (tcphdr->th_dport));
654 udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2));
655 sprintf (buf, "[UDP] %s:%d -> %s:%d",
657 ntohs (udphdr->uh_sport),
659 ntohs (udphdr->uh_dport));
663 icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2));
664 sprintf (buf, "[ICMP] %s -> %s %u(%u)",
672 sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst);
680 SetAliasAddressFromIfName(const char *ifn)
684 char *buf, *lim, *next;
685 struct if_msghdr *ifm;
686 struct ifa_msghdr *ifam;
687 struct sockaddr_dl *sdl;
688 struct sockaddr_in *sin;
693 mib[3] = AF_INET; /* Only IP addresses please */
694 mib[4] = NET_RT_IFLIST;
695 mib[5] = 0; /* ifIndex??? */
697 * Get interface data.
699 if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
700 err(1, "iflist-sysctl-estimate");
701 if ((buf = malloc(needed)) == NULL)
702 errx(1, "malloc failed");
703 if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
704 err(1, "iflist-sysctl-get");
707 * Loop through interfaces until one with
708 * given name is found. This is done to
709 * find correct interface index for routing
710 * message processing.
715 ifm = (struct if_msghdr *)next;
716 next += ifm->ifm_msglen;
717 if (ifm->ifm_version != RTM_VERSION) {
719 warnx("routing message version %d "
720 "not understood", ifm->ifm_version);
723 if (ifm->ifm_type == RTM_IFINFO) {
724 sdl = (struct sockaddr_dl *)(ifm + 1);
725 if (strlen(ifn) == sdl->sdl_nlen &&
726 strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) {
727 ifIndex = ifm->ifm_index;
728 ifMTU = ifm->ifm_data.ifi_mtu;
734 errx(1, "unknown interface name %s", ifn);
736 * Get interface address.
740 ifam = (struct ifa_msghdr *)next;
741 next += ifam->ifam_msglen;
742 if (ifam->ifam_version != RTM_VERSION) {
744 warnx("routing message version %d "
745 "not understood", ifam->ifam_version);
748 if (ifam->ifam_type != RTM_NEWADDR)
750 if (ifam->ifam_addrs & RTA_IFA) {
752 char *cp = (char *)(ifam + 1);
755 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
756 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
758 for (i = 1; i < RTA_IFA; i <<= 1)
759 if (ifam->ifam_addrs & i)
760 ADVANCE(cp, (struct sockaddr *)cp);
761 if (((struct sockaddr *)cp)->sa_family == AF_INET) {
762 sin = (struct sockaddr_in *)cp;
768 errx(1, "%s: cannot get interface address", ifn);
770 PacketAliasSetAddress(sin->sin_addr);
771 syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes",
772 inet_ntoa(sin->sin_addr), ifMTU);
777 void Quit (const char* msg)
783 void Warn (const char* msg)
786 syslog (LOG_ALERT, "%s (%m)", msg);
791 static void RefreshAddr (int sig)
797 static void InitiateShutdown (int sig)
800 * Start timer to allow kernel gracefully
801 * shutdown existing connections when system
804 siginterrupt(SIGALRM, 1);
805 signal (SIGALRM, Shutdown);
809 static void Shutdown (int sig)
815 * Different options recognized by this program.
851 * Option information structure (used by ParseOption).
859 const char* parmDescription;
860 const char* description;
862 const char* shortName;
866 * Table of known options.
869 static struct OptionInfo optionTable[] = {
872 PKT_ALIAS_UNREGISTERED_ONLY,
875 "alias only unregistered addresses",
888 PKT_ALIAS_PROXY_ONLY,
899 "operate in reverse mode",
904 PKT_ALIAS_DENY_INCOMING,
907 "allow incoming connections",
912 PKT_ALIAS_USE_SOCKETS,
915 "use sockets to inhibit port conflict",
920 PKT_ALIAS_SAME_PORTS,
923 "try to keep original port numbers for connections",
931 "verbose mode, dump packet information",
939 "dynamic mode, automatically detect interface address changes",
946 "number|service_name",
947 "set port for incoming packets",
954 "number|service_name",
955 "set port for outgoing packets",
962 "number|service_name",
963 "set port (defaults to natd/divert)",
971 "address to use for aliasing",
979 "address to use for incoming sessions",
987 "take aliasing address from interface",
994 "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
996 "add transparent proxying / destination NAT",
1003 "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
1004 " [remote_addr[:remote_port_range]]",
1005 "redirect a port (or ports) for incoming traffic",
1012 "proto local_addr [public_addr] [remote_addr]",
1013 "redirect packets of a given proto",
1020 "local_addr[,...] public_addr",
1021 "define mapping between local and public addresses",
1029 "read options from configuration file",
1037 "enable logging of denied incoming packets",
1045 "name of syslog facility to use for logging",
1053 "punch holes in the firewall for incoming FTP/IRC DCC connections",
1061 "log packets converted by natd, but denied by ipfw",
1066 static void ParseOption (const char* option, const char* parms)
1069 struct OptionInfo* info;
1074 const char* strValue;
1075 struct in_addr addrValue;
1078 CODE* fac_record = NULL;
1080 * Find option from table.
1082 max = sizeof (optionTable) / sizeof (struct OptionInfo);
1083 for (i = 0, info = optionTable; i < max; i++, info++) {
1085 if (!strcmp (info->name, option))
1088 if (info->shortName)
1089 if (!strcmp (info->shortName, option))
1095 warnx ("unknown option %s", option);
1106 switch (info->parm) {
1111 if (!strcmp (parms, "yes"))
1114 if (!strcmp (parms, "no"))
1117 errx (1, "%s needs yes/no parameter", option);
1122 errx (1, "%s needs service name or "
1123 "port number parameter",
1126 uNumValue = StrToPort (parms, "divert");
1131 numValue = strtol (parms, &end, 10);
1136 errx (1, "%s needs numeric parameter", option);
1142 errx (1, "%s needs parameter", option);
1147 errx (1, "%s does not take parameters", option);
1152 errx (1, "%s needs address/host parameter", option);
1154 StrToAddr (parms, &addrValue);
1158 switch (info->type) {
1159 case PacketAliasOption:
1161 aliasValue = yesNoValue ? info->packetAliasOpt : 0;
1162 PacketAliasSetMode (aliasValue, info->packetAliasOpt);
1166 verbose = yesNoValue;
1170 dynamicMode = yesNoValue;
1178 outPort = uNumValue;
1182 inOutPort = uNumValue;
1186 memcpy (&aliasAddr, &addrValue, sizeof (struct in_addr));
1190 PacketAliasSetTarget(addrValue);
1194 SetupPortRedirect (strValue);
1198 SetupProtoRedirect(strValue);
1201 case RedirectAddress:
1202 SetupAddressRedirect (strValue);
1206 PacketAliasProxyRule (strValue);
1213 ifName = strdup (strValue);
1217 ReadConfigFile (strValue);
1221 logDropped = yesNoValue;
1226 fac_record = facilitynames;
1227 while (fac_record->c_name != NULL) {
1229 if (!strcmp (fac_record->c_name, strValue)) {
1231 logFacility = fac_record->c_val;
1239 if(fac_record->c_name == NULL)
1240 errx(1, "Unknown log facility name: %s", strValue);
1245 SetupPunchFW(strValue);
1249 logIpfwDenied = yesNoValue;;
1254 void ReadConfigFile (const char* fileName)
1262 file = fopen (fileName, "r");
1264 err(1, "cannot open config file %s", fileName);
1266 while ((buf = fgetln(file, &len)) != NULL) {
1267 if (buf[len - 1] == '\n')
1268 buf[len - 1] = '\0';
1270 errx(1, "config file format error: "
1271 "last line should end with newline");
1274 * Check for comments, strip off trailing spaces.
1276 if ((ptr = strchr(buf, '#')))
1278 for (ptr = buf; isspace(*ptr); ++ptr)
1282 for (p = strchr(buf, '\0'); isspace(*--p);)
1287 * Extract option name.
1290 while (*ptr && !isspace (*ptr))
1299 * Skip white space between name and parms.
1301 while (*ptr && isspace (*ptr))
1304 ParseOption (option, *ptr ? ptr : NULL);
1310 static void Usage (void)
1314 struct OptionInfo* info;
1316 fprintf (stderr, "Recognized options:\n\n");
1318 max = sizeof (optionTable) / sizeof (struct OptionInfo);
1319 for (i = 0, info = optionTable; i < max; i++, info++) {
1321 fprintf (stderr, "-%-20s %s\n", info->name,
1322 info->parmDescription);
1324 if (info->shortName)
1325 fprintf (stderr, "-%-20s %s\n", info->shortName,
1326 info->parmDescription);
1328 fprintf (stderr, " %s\n\n", info->description);
1334 void SetupPortRedirect (const char* parms)
1339 struct in_addr localAddr;
1340 struct in_addr publicAddr;
1341 struct in_addr remoteAddr;
1342 port_range portRange;
1343 u_short localPort = 0;
1344 u_short publicPort = 0;
1345 u_short remotePort = 0;
1346 u_short numLocalPorts = 0;
1347 u_short numPublicPorts = 0;
1348 u_short numRemotePorts = 0;
1353 struct alias_link *link = NULL;
1355 strcpy (buf, parms);
1359 protoName = strtok (buf, " \t");
1361 errx (1, "redirect_port: missing protocol");
1363 proto = StrToProto (protoName);
1365 * Extract local address.
1367 ptr = strtok (NULL, " \t");
1369 errx (1, "redirect_port: missing local address");
1371 separator = strchr(ptr, ',');
1372 if (separator) { /* LSNAT redirection syntax. */
1373 localAddr.s_addr = INADDR_NONE;
1378 if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 )
1379 errx (1, "redirect_port: invalid local port range");
1381 localPort = GETLOPORT(portRange);
1382 numLocalPorts = GETNUMPORTS(portRange);
1387 * Extract public port and optionally address.
1389 ptr = strtok (NULL, " \t");
1391 errx (1, "redirect_port: missing public port");
1393 separator = strchr (ptr, ':');
1395 if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 )
1396 errx (1, "redirect_port: invalid public port range");
1399 publicAddr.s_addr = INADDR_ANY;
1400 if (StrToPortRange (ptr, protoName, &portRange) != 0)
1401 errx (1, "redirect_port: invalid public port range");
1404 publicPort = GETLOPORT(portRange);
1405 numPublicPorts = GETNUMPORTS(portRange);
1408 * Extract remote address and optionally port.
1410 ptr = strtok (NULL, " \t");
1412 separator = strchr (ptr, ':');
1414 if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0)
1415 errx (1, "redirect_port: invalid remote port range");
1417 SETLOPORT(portRange, 0);
1418 SETNUMPORTS(portRange, 1);
1419 StrToAddr (ptr, &remoteAddr);
1423 SETLOPORT(portRange, 0);
1424 SETNUMPORTS(portRange, 1);
1425 remoteAddr.s_addr = INADDR_ANY;
1428 remotePort = GETLOPORT(portRange);
1429 numRemotePorts = GETNUMPORTS(portRange);
1432 * Make sure port ranges match up, then add the redirect ports.
1434 if (numLocalPorts != numPublicPorts)
1435 errx (1, "redirect_port: port ranges must be equal in size");
1437 /* Remote port range is allowed to be '0' which means all ports. */
1438 if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0))
1439 errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
1441 for (i = 0 ; i < numPublicPorts ; ++i) {
1442 /* If remotePort is all ports, set it to 0. */
1443 u_short remotePortCopy = remotePort + i;
1444 if (numRemotePorts == 1 && remotePort == 0)
1447 link = PacketAliasRedirectPort (localAddr,
1448 htons(localPort + i),
1450 htons(remotePortCopy),
1452 htons(publicPort + i),
1457 * Setup LSNAT server pool.
1459 if (serverPool != NULL && link != NULL) {
1460 ptr = strtok(serverPool, ",");
1461 while (ptr != NULL) {
1462 if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0)
1463 errx(1, "redirect_port: invalid local port range");
1465 localPort = GETLOPORT(portRange);
1466 if (GETNUMPORTS(portRange) != 1)
1467 errx(1, "redirect_port: local port must be single in this context");
1468 PacketAliasAddServer(link, localAddr, htons(localPort));
1469 ptr = strtok(NULL, ",");
1475 SetupProtoRedirect(const char* parms)
1479 struct in_addr localAddr;
1480 struct in_addr publicAddr;
1481 struct in_addr remoteAddr;
1484 struct protoent *protoent;
1486 strcpy (buf, parms);
1490 protoName = strtok(buf, " \t");
1492 errx(1, "redirect_proto: missing protocol");
1494 protoent = getprotobyname(protoName);
1495 if (protoent == NULL)
1496 errx(1, "redirect_proto: unknown protocol %s", protoName);
1498 proto = protoent->p_proto;
1500 * Extract local address.
1502 ptr = strtok(NULL, " \t");
1504 errx(1, "redirect_proto: missing local address");
1506 StrToAddr(ptr, &localAddr);
1508 * Extract optional public address.
1510 ptr = strtok(NULL, " \t");
1512 StrToAddr(ptr, &publicAddr);
1514 publicAddr.s_addr = INADDR_ANY;
1516 * Extract optional remote address.
1518 ptr = strtok(NULL, " \t");
1520 StrToAddr(ptr, &remoteAddr);
1522 remoteAddr.s_addr = INADDR_ANY;
1524 * Create aliasing link.
1526 (void)PacketAliasRedirectProto(localAddr, remoteAddr, publicAddr,
1530 void SetupAddressRedirect (const char* parms)
1535 struct in_addr localAddr;
1536 struct in_addr publicAddr;
1538 struct alias_link *link;
1540 strcpy (buf, parms);
1542 * Extract local address.
1544 ptr = strtok (buf, " \t");
1546 errx (1, "redirect_address: missing local address");
1548 separator = strchr(ptr, ',');
1549 if (separator) { /* LSNAT redirection syntax. */
1550 localAddr.s_addr = INADDR_NONE;
1553 StrToAddr (ptr, &localAddr);
1557 * Extract public address.
1559 ptr = strtok (NULL, " \t");
1561 errx (1, "redirect_address: missing public address");
1563 StrToAddr (ptr, &publicAddr);
1564 link = PacketAliasRedirectAddr(localAddr, publicAddr);
1567 * Setup LSNAT server pool.
1569 if (serverPool != NULL && link != NULL) {
1570 ptr = strtok(serverPool, ",");
1571 while (ptr != NULL) {
1572 StrToAddr(ptr, &localAddr);
1573 PacketAliasAddServer(link, localAddr, htons(~0));
1574 ptr = strtok(NULL, ",");
1579 void StrToAddr (const char* str, struct in_addr* addr)
1583 if (inet_aton (str, addr))
1586 hp = gethostbyname (str);
1588 errx (1, "unknown host %s", str);
1590 memcpy (addr, hp->h_addr, sizeof (struct in_addr));
1593 u_short StrToPort (const char* str, const char* proto)
1599 port = strtol (str, &end, 10);
1601 return htons (port);
1603 sp = getservbyname (str, proto);
1605 errx (1, "unknown service %s/%s", str, proto);
1610 int StrToPortRange (const char* str, const char* proto, port_range *portRange)
1618 /* First see if this is a service, return corresponding port if so. */
1619 sp = getservbyname (str,proto);
1621 SETLOPORT(*portRange, ntohs(sp->s_port));
1622 SETNUMPORTS(*portRange, 1);
1626 /* Not a service, see if it's a single port or port range. */
1627 sep = strchr (str, '-');
1629 SETLOPORT(*portRange, strtol(str, &end, 10));
1632 SETNUMPORTS(*portRange, 1);
1636 /* Error in port range field. */
1637 errx (1, "unknown service %s/%s", str, proto);
1640 /* Port range, get the values and sanity check. */
1641 sscanf (str, "%hu-%hu", &loPort, &hiPort);
1642 SETLOPORT(*portRange, loPort);
1643 SETNUMPORTS(*portRange, 0); /* Error by default */
1644 if (loPort <= hiPort)
1645 SETNUMPORTS(*portRange, hiPort - loPort + 1);
1647 if (GETNUMPORTS(*portRange) == 0)
1648 errx (1, "invalid port range %s", str);
1654 int StrToProto (const char* str)
1656 if (!strcmp (str, "tcp"))
1659 if (!strcmp (str, "udp"))
1662 errx (1, "unknown protocol %s. Expected tcp or udp", str);
1665 int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange)
1669 ptr = strchr (str, ':');
1671 errx (1, "%s is missing port number", str);
1676 StrToAddr (str, addr);
1677 return StrToPortRange (ptr, proto, portRange);
1681 SetupPunchFW(const char *strValue)
1683 unsigned int base, num;
1685 if (sscanf(strValue, "%u:%u", &base, &num) != 2)
1686 errx(1, "punch_fw: basenumber:count parameter required");
1688 PacketAliasSetFWBase(base, num);
1689 (void)PacketAliasSetMode(PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);