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>
17 #include <sys/types.h>
18 #include <sys/socket.h>
19 #include <sys/sysctl.h>
22 #include <netinet/in.h>
23 #include <netinet/in_systm.h>
24 #include <netinet/ip.h>
25 #include <machine/in_cksum.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 FlushPacketBuffer (int fd);
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 char packetBuf[IP_MAXPACKET];
122 static int packetLen;
123 static struct sockaddr_in packetAddr;
124 static int packetSock;
125 static int packetDirection;
126 static int dropIgnoredIncoming;
127 static int logDropped;
128 static int logFacility;
129 static int logIpfwDenied;
131 int main (int argc, char** argv)
137 struct sockaddr_in addr;
142 * Initialize packet aliasing software.
143 * Done already here to be able to alter option bits
144 * during command line and configuration file processing.
159 aliasAddr.s_addr = INADDR_NONE;
163 logFacility = LOG_DAEMON;
166 * Mark packet buffer empty.
169 packetDirection = DONT_KNOW;
171 ParseArgs (argc, argv);
173 * Open syslog channel.
175 openlog ("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0),
178 * Check that valid aliasing address has been given.
180 if (aliasAddr.s_addr == INADDR_NONE && ifName == NULL)
181 errx (1, "aliasing address not given");
183 if (aliasAddr.s_addr != INADDR_NONE && ifName != NULL)
184 errx (1, "both alias address and interface "
185 "name are not allowed");
187 * Check that valid port number is known.
189 if (inPort != 0 || outPort != 0)
190 if (inPort == 0 || outPort == 0)
191 errx (1, "both input and output ports are required");
193 if (inPort == 0 && outPort == 0 && inOutPort == 0)
194 ParseOption ("port", DEFAULT_SERVICE);
197 * Check if ignored packets should be dropped.
199 dropIgnoredIncoming = PacketAliasSetMode (0, 0);
200 dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING;
202 * Create divert sockets. Use only one socket if -p was specified
203 * on command line. Otherwise, create separate sockets for
204 * outgoing and incoming connnections.
208 divertInOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
209 if (divertInOut == -1)
210 Quit ("Unable to create divert socket.");
218 addr.sin_family = AF_INET;
219 addr.sin_addr.s_addr = INADDR_ANY;
220 addr.sin_port = inOutPort;
222 if (bind (divertInOut,
223 (struct sockaddr*) &addr,
225 Quit ("Unable to bind divert socket.");
229 divertIn = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
231 Quit ("Unable to create incoming divert socket.");
233 divertOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
235 Quit ("Unable to create outgoing divert socket.");
240 * Bind divert sockets.
243 addr.sin_family = AF_INET;
244 addr.sin_addr.s_addr = INADDR_ANY;
245 addr.sin_port = inPort;
248 (struct sockaddr*) &addr,
250 Quit ("Unable to bind incoming divert socket.");
252 addr.sin_family = AF_INET;
253 addr.sin_addr.s_addr = INADDR_ANY;
254 addr.sin_port = outPort;
257 (struct sockaddr*) &addr,
259 Quit ("Unable to bind outgoing divert socket.");
262 * Create routing socket if interface name specified and in dynamic mode.
268 routeSock = socket (PF_ROUTE, SOCK_RAW, 0);
270 Quit ("Unable to create routing info socket.");
275 SetAliasAddressFromIfName (ifName);
278 * Create socket for sending ICMP messages.
280 icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
282 Quit ("Unable to create ICMP socket.");
285 * And disable reads for the socket, otherwise it slowly fills
286 * up with received icmps which we do not use.
288 shutdown(icmpSock, SHUT_RD);
291 * Become a daemon unless verbose mode was requested.
296 * Catch signals to manage shutdown and
297 * refresh of interface address.
299 siginterrupt(SIGTERM, 1);
300 siginterrupt(SIGHUP, 1);
301 signal (SIGTERM, InitiateShutdown);
302 signal (SIGHUP, RefreshAddr);
304 * Set alias address if it has been given.
306 if (aliasAddr.s_addr != INADDR_NONE)
307 PacketAliasSetAddress (aliasAddr);
309 * We need largest descriptor number for select.
314 if (divertIn > fdMax)
317 if (divertOut > fdMax)
320 if (divertInOut > fdMax)
323 if (routeSock > fdMax)
328 if (divertInOut != -1 && !ifName && packetSock == -1) {
330 * When using only one socket, just call
331 * DoAliasing repeatedly to process packets.
333 DoAliasing (divertInOut, DONT_KNOW);
337 * Build read mask from socket descriptors to select.
340 FD_ZERO (&writeMask);
343 * If there is unsent packet in buffer, use select
344 * to check when socket comes writable again.
346 if (packetSock != -1) {
348 FD_SET (packetSock, &writeMask);
352 * No unsent packet exists - safe to check if
353 * new ones are available.
356 FD_SET (divertIn, &readMask);
359 FD_SET (divertOut, &readMask);
361 if (divertInOut != -1)
362 FD_SET (divertInOut, &readMask);
365 * Routing info is processed always.
368 FD_SET (routeSock, &readMask);
370 if (select (fdMax + 1,
379 Quit ("Select failed.");
382 if (packetSock != -1)
383 if (FD_ISSET (packetSock, &writeMask))
384 FlushPacketBuffer (packetSock);
387 if (FD_ISSET (divertIn, &readMask))
388 DoAliasing (divertIn, INPUT);
391 if (FD_ISSET (divertOut, &readMask))
392 DoAliasing (divertOut, OUTPUT);
394 if (divertInOut != -1)
395 if (FD_ISSET (divertInOut, &readMask))
396 DoAliasing (divertInOut, DONT_KNOW);
399 if (FD_ISSET (routeSock, &readMask))
400 HandleRoutingInfo (routeSock);
409 static void DaemonMode ()
416 pidFile = fopen (PIDFILE, "w");
419 fprintf (pidFile, "%d\n", getpid ());
424 static void ParseArgs (int argc, char** argv)
429 int len; /* bounds checking */
431 for (arg = 1; arg < argc; arg++) {
436 warnx ("invalid option %s", opt);
443 while (arg < argc - 1) {
445 if (argv[arg + 1][0] == '-')
449 strncat (parmBuf, " ", sizeof(parmBuf) - (len + 1));
450 len += strlen(parmBuf + len);
454 strncat (parmBuf, argv[arg], sizeof(parmBuf) - (len + 1));
455 len += strlen(parmBuf + len);
459 ParseOption (opt + 1, (len ? parmBuf : NULL));
464 static void DoAliasing (int fd, int direction)
472 if (assignAliasAddr) {
474 SetAliasAddressFromIfName (ifName);
478 * Get packet from socket.
480 addrSize = sizeof packetAddr;
481 origBytes = recvfrom (fd,
485 (struct sockaddr*) &packetAddr,
488 if (origBytes == -1) {
491 Warn ("read from divert socket failed");
496 * This is a IP packet.
498 ip = (struct ip*) packetBuf;
499 if (direction == DONT_KNOW) {
500 if (packetAddr.sin_addr.s_addr == INADDR_ANY)
508 * Print packet direction and protocol type.
510 printf (direction == OUTPUT ? "Out " : "In ");
526 printf ("[%d] ", ip->ip_p);
535 if (direction == OUTPUT) {
537 * Outgoing packets. Do aliasing.
539 PacketAliasOut (packetBuf, IP_MAXPACKET);
546 status = PacketAliasIn (packetBuf, IP_MAXPACKET);
547 if (status == PKT_ALIAS_IGNORED &&
548 dropIgnoredIncoming) {
551 printf (" dropped.\n");
554 SyslogPacket (ip, LOG_WARNING, "denied");
560 * Length might have changed during aliasing.
562 bytes = ntohs (ip->ip_len);
564 * Update alias overhead size for outgoing packets.
566 if (direction == OUTPUT &&
567 bytes - origBytes > aliasOverhead)
568 aliasOverhead = bytes - origBytes;
573 * Print addresses after aliasing.
575 printf (" aliased to\n");
583 packetDirection = direction;
585 FlushPacketBuffer (fd);
588 static void FlushPacketBuffer (int fd)
593 * Put packet back for processing.
599 (struct sockaddr*) &packetAddr,
602 if (wrote != packetLen) {
604 * If buffer space is not available,
605 * just return. Main loop will take care of
606 * retrying send when space becomes available.
608 if (errno == ENOBUFS)
611 if (errno == EMSGSIZE) {
613 if (packetDirection == OUTPUT &&
615 SendNeedFragIcmp (icmpSock,
616 (struct ip*) packetBuf,
617 ifMTU - aliasOverhead);
619 else if (errno == EACCES && logIpfwDenied) {
621 sprintf (msgBuf, "failed to write packet back");
629 static void HandleRoutingInfo (int fd)
632 struct if_msghdr ifMsg;
634 * Get packet from socket.
636 bytes = read (fd, &ifMsg, sizeof ifMsg);
639 Warn ("read from routing socket failed");
643 if (ifMsg.ifm_version != RTM_VERSION) {
645 Warn ("unexpected packet read from routing socket");
650 printf ("Routing message %#x received.\n", ifMsg.ifm_type);
652 if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO) &&
653 ifMsg.ifm_index == ifIndex) {
655 printf("Interface address/MTU has probably changed.\n");
660 static void PrintPacket (struct ip* ip)
662 printf ("%s", FormatPacket (ip));
665 static void SyslogPacket (struct ip* ip, int priority, const char *label)
667 syslog (priority, "%s %s", label, FormatPacket (ip));
670 static char* FormatPacket (struct ip* ip)
672 static char buf[256];
673 struct tcphdr* tcphdr;
674 struct udphdr* udphdr;
675 struct icmp* icmphdr;
679 strcpy (src, inet_ntoa (ip->ip_src));
680 strcpy (dst, inet_ntoa (ip->ip_dst));
684 tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2));
685 sprintf (buf, "[TCP] %s:%d -> %s:%d",
687 ntohs (tcphdr->th_sport),
689 ntohs (tcphdr->th_dport));
693 udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2));
694 sprintf (buf, "[UDP] %s:%d -> %s:%d",
696 ntohs (udphdr->uh_sport),
698 ntohs (udphdr->uh_dport));
702 icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2));
703 sprintf (buf, "[ICMP] %s -> %s %u(%u)",
711 sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst);
719 SetAliasAddressFromIfName(const char *ifn)
723 char *buf, *lim, *next;
724 struct if_msghdr *ifm;
725 struct ifa_msghdr *ifam;
726 struct sockaddr_dl *sdl;
727 struct sockaddr_in *sin;
732 mib[3] = AF_INET; /* Only IP addresses please */
733 mib[4] = NET_RT_IFLIST;
734 mib[5] = 0; /* ifIndex??? */
736 * Get interface data.
738 if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
739 err(1, "iflist-sysctl-estimate");
740 if ((buf = malloc(needed)) == NULL)
741 errx(1, "malloc failed");
742 if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
743 err(1, "iflist-sysctl-get");
746 * Loop through interfaces until one with
747 * given name is found. This is done to
748 * find correct interface index for routing
749 * message processing.
754 ifm = (struct if_msghdr *)next;
755 next += ifm->ifm_msglen;
756 if (ifm->ifm_version != RTM_VERSION) {
758 warnx("routing message version %d "
759 "not understood", ifm->ifm_version);
762 if (ifm->ifm_type == RTM_IFINFO) {
763 sdl = (struct sockaddr_dl *)(ifm + 1);
764 if (strlen(ifn) == sdl->sdl_nlen &&
765 strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) {
766 ifIndex = ifm->ifm_index;
767 ifMTU = ifm->ifm_data.ifi_mtu;
773 errx(1, "unknown interface name %s", ifn);
775 * Get interface address.
779 ifam = (struct ifa_msghdr *)next;
780 next += ifam->ifam_msglen;
781 if (ifam->ifam_version != RTM_VERSION) {
783 warnx("routing message version %d "
784 "not understood", ifam->ifam_version);
787 if (ifam->ifam_type != RTM_NEWADDR)
789 if (ifam->ifam_addrs & RTA_IFA) {
791 char *cp = (char *)(ifam + 1);
794 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
795 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
797 for (i = 1; i < RTA_IFA; i <<= 1)
798 if (ifam->ifam_addrs & i)
799 ADVANCE(cp, (struct sockaddr *)cp);
800 if (((struct sockaddr *)cp)->sa_family == AF_INET) {
801 sin = (struct sockaddr_in *)cp;
807 errx(1, "%s: cannot get interface address", ifn);
809 PacketAliasSetAddress(sin->sin_addr);
810 syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes",
811 inet_ntoa(sin->sin_addr), ifMTU);
816 void Quit (const char* msg)
822 void Warn (const char* msg)
825 syslog (LOG_ALERT, "%s (%m)", msg);
830 static void RefreshAddr (int sig)
836 static void InitiateShutdown (int sig)
839 * Start timer to allow kernel gracefully
840 * shutdown existing connections when system
843 siginterrupt(SIGALRM, 1);
844 signal (SIGALRM, Shutdown);
848 static void Shutdown (int sig)
854 * Different options recognized by this program.
890 * Option information structure (used by ParseOption).
898 const char* parmDescription;
899 const char* description;
901 const char* shortName;
905 * Table of known options.
908 static struct OptionInfo optionTable[] = {
911 PKT_ALIAS_UNREGISTERED_ONLY,
914 "alias only unregistered addresses",
927 PKT_ALIAS_PROXY_ONLY,
938 "operate in reverse mode",
943 PKT_ALIAS_DENY_INCOMING,
946 "allow incoming connections",
951 PKT_ALIAS_USE_SOCKETS,
954 "use sockets to inhibit port conflict",
959 PKT_ALIAS_SAME_PORTS,
962 "try to keep original port numbers for connections",
970 "verbose mode, dump packet information",
978 "dynamic mode, automatically detect interface address changes",
985 "number|service_name",
986 "set port for incoming packets",
993 "number|service_name",
994 "set port for outgoing packets",
1001 "number|service_name",
1002 "set port (defaults to natd/divert)",
1010 "address to use for aliasing",
1018 "address to use for incoming sessions",
1026 "take aliasing address from interface",
1033 "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
1035 "add transparent proxying / destination NAT",
1042 "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
1043 " [remote_addr[:remote_port_range]]",
1044 "redirect a port (or ports) for incoming traffic",
1051 "proto local_addr [public_addr] [remote_addr]",
1052 "redirect packets of a given proto",
1059 "local_addr[,...] public_addr",
1060 "define mapping between local and public addresses",
1068 "read options from configuration file",
1076 "enable logging of denied incoming packets",
1084 "name of syslog facility to use for logging",
1092 "punch holes in the firewall for incoming FTP/IRC DCC connections",
1100 "log packets converted by natd, but denied by ipfw",
1105 static void ParseOption (const char* option, const char* parms)
1108 struct OptionInfo* info;
1113 const char* strValue;
1114 struct in_addr addrValue;
1117 CODE* fac_record = NULL;
1119 * Find option from table.
1121 max = sizeof (optionTable) / sizeof (struct OptionInfo);
1122 for (i = 0, info = optionTable; i < max; i++, info++) {
1124 if (!strcmp (info->name, option))
1127 if (info->shortName)
1128 if (!strcmp (info->shortName, option))
1134 warnx ("unknown option %s", option);
1145 switch (info->parm) {
1150 if (!strcmp (parms, "yes"))
1153 if (!strcmp (parms, "no"))
1156 errx (1, "%s needs yes/no parameter", option);
1161 errx (1, "%s needs service name or "
1162 "port number parameter",
1165 uNumValue = StrToPort (parms, "divert");
1170 numValue = strtol (parms, &end, 10);
1175 errx (1, "%s needs numeric parameter", option);
1181 errx (1, "%s needs parameter", option);
1186 errx (1, "%s does not take parameters", option);
1191 errx (1, "%s needs address/host parameter", option);
1193 StrToAddr (parms, &addrValue);
1197 switch (info->type) {
1198 case PacketAliasOption:
1200 aliasValue = yesNoValue ? info->packetAliasOpt : 0;
1201 PacketAliasSetMode (aliasValue, info->packetAliasOpt);
1205 verbose = yesNoValue;
1209 dynamicMode = yesNoValue;
1217 outPort = uNumValue;
1221 inOutPort = uNumValue;
1225 memcpy (&aliasAddr, &addrValue, sizeof (struct in_addr));
1229 PacketAliasSetTarget(addrValue);
1233 SetupPortRedirect (strValue);
1237 SetupProtoRedirect(strValue);
1240 case RedirectAddress:
1241 SetupAddressRedirect (strValue);
1245 PacketAliasProxyRule (strValue);
1252 ifName = strdup (strValue);
1256 ReadConfigFile (strValue);
1260 logDropped = yesNoValue;
1265 fac_record = facilitynames;
1266 while (fac_record->c_name != NULL) {
1268 if (!strcmp (fac_record->c_name, strValue)) {
1270 logFacility = fac_record->c_val;
1278 if(fac_record->c_name == NULL)
1279 errx(1, "Unknown log facility name: %s", strValue);
1284 SetupPunchFW(strValue);
1288 logIpfwDenied = yesNoValue;;
1293 void ReadConfigFile (const char* fileName)
1301 file = fopen (fileName, "r");
1303 err(1, "cannot open config file %s", fileName);
1305 while ((buf = fgetln(file, &len)) != NULL) {
1306 if (buf[len - 1] == '\n')
1307 buf[len - 1] = '\0';
1309 errx(1, "config file format error: "
1310 "last line should end with newline");
1313 * Check for comments, strip off trailing spaces.
1315 if ((ptr = strchr(buf, '#')))
1317 for (ptr = buf; isspace(*ptr); ++ptr)
1321 for (p = strchr(buf, '\0'); isspace(*--p);)
1326 * Extract option name.
1329 while (*ptr && !isspace (*ptr))
1338 * Skip white space between name and parms.
1340 while (*ptr && isspace (*ptr))
1343 ParseOption (option, *ptr ? ptr : NULL);
1349 static void Usage ()
1353 struct OptionInfo* info;
1355 fprintf (stderr, "Recognized options:\n\n");
1357 max = sizeof (optionTable) / sizeof (struct OptionInfo);
1358 for (i = 0, info = optionTable; i < max; i++, info++) {
1360 fprintf (stderr, "-%-20s %s\n", info->name,
1361 info->parmDescription);
1363 if (info->shortName)
1364 fprintf (stderr, "-%-20s %s\n", info->shortName,
1365 info->parmDescription);
1367 fprintf (stderr, " %s\n\n", info->description);
1373 void SetupPortRedirect (const char* parms)
1378 struct in_addr localAddr;
1379 struct in_addr publicAddr;
1380 struct in_addr remoteAddr;
1381 port_range portRange;
1382 u_short localPort = 0;
1383 u_short publicPort = 0;
1384 u_short remotePort = 0;
1385 u_short numLocalPorts = 0;
1386 u_short numPublicPorts = 0;
1387 u_short numRemotePorts = 0;
1392 struct alias_link *link = NULL;
1394 strcpy (buf, parms);
1398 protoName = strtok (buf, " \t");
1400 errx (1, "redirect_port: missing protocol");
1402 proto = StrToProto (protoName);
1404 * Extract local address.
1406 ptr = strtok (NULL, " \t");
1408 errx (1, "redirect_port: missing local address");
1410 separator = strchr(ptr, ',');
1411 if (separator) { /* LSNAT redirection syntax. */
1412 localAddr.s_addr = INADDR_NONE;
1417 if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 )
1418 errx (1, "redirect_port: invalid local port range");
1420 localPort = GETLOPORT(portRange);
1421 numLocalPorts = GETNUMPORTS(portRange);
1426 * Extract public port and optionally address.
1428 ptr = strtok (NULL, " \t");
1430 errx (1, "redirect_port: missing public port");
1432 separator = strchr (ptr, ':');
1434 if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 )
1435 errx (1, "redirect_port: invalid public port range");
1438 publicAddr.s_addr = INADDR_ANY;
1439 if (StrToPortRange (ptr, protoName, &portRange) != 0)
1440 errx (1, "redirect_port: invalid public port range");
1443 publicPort = GETLOPORT(portRange);
1444 numPublicPorts = GETNUMPORTS(portRange);
1447 * Extract remote address and optionally port.
1449 ptr = strtok (NULL, " \t");
1451 separator = strchr (ptr, ':');
1453 if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0)
1454 errx (1, "redirect_port: invalid remote port range");
1456 SETLOPORT(portRange, 0);
1457 SETNUMPORTS(portRange, 1);
1458 StrToAddr (ptr, &remoteAddr);
1462 SETLOPORT(portRange, 0);
1463 SETNUMPORTS(portRange, 1);
1464 remoteAddr.s_addr = INADDR_ANY;
1467 remotePort = GETLOPORT(portRange);
1468 numRemotePorts = GETNUMPORTS(portRange);
1471 * Make sure port ranges match up, then add the redirect ports.
1473 if (numLocalPorts != numPublicPorts)
1474 errx (1, "redirect_port: port ranges must be equal in size");
1476 /* Remote port range is allowed to be '0' which means all ports. */
1477 if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0))
1478 errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
1480 for (i = 0 ; i < numPublicPorts ; ++i) {
1481 /* If remotePort is all ports, set it to 0. */
1482 u_short remotePortCopy = remotePort + i;
1483 if (numRemotePorts == 1 && remotePort == 0)
1486 link = PacketAliasRedirectPort (localAddr,
1487 htons(localPort + i),
1489 htons(remotePortCopy),
1491 htons(publicPort + i),
1496 * Setup LSNAT server pool.
1498 if (serverPool != NULL && link != NULL) {
1499 ptr = strtok(serverPool, ",");
1500 while (ptr != NULL) {
1501 if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0)
1502 errx(1, "redirect_port: invalid local port range");
1504 localPort = GETLOPORT(portRange);
1505 if (GETNUMPORTS(portRange) != 1)
1506 errx(1, "redirect_port: local port must be single in this context");
1507 PacketAliasAddServer(link, localAddr, htons(localPort));
1508 ptr = strtok(NULL, ",");
1514 SetupProtoRedirect(const char* parms)
1518 struct in_addr localAddr;
1519 struct in_addr publicAddr;
1520 struct in_addr remoteAddr;
1523 struct protoent *protoent;
1525 strcpy (buf, parms);
1529 protoName = strtok(buf, " \t");
1531 errx(1, "redirect_proto: missing protocol");
1533 protoent = getprotobyname(protoName);
1534 if (protoent == NULL)
1535 errx(1, "redirect_proto: unknown protocol %s", protoName);
1537 proto = protoent->p_proto;
1539 * Extract local address.
1541 ptr = strtok(NULL, " \t");
1543 errx(1, "redirect_proto: missing local address");
1545 StrToAddr(ptr, &localAddr);
1547 * Extract optional public address.
1549 ptr = strtok(NULL, " \t");
1551 StrToAddr(ptr, &publicAddr);
1553 publicAddr.s_addr = INADDR_ANY;
1555 * Extract optional remote address.
1557 ptr = strtok(NULL, " \t");
1559 StrToAddr(ptr, &remoteAddr);
1561 remoteAddr.s_addr = INADDR_ANY;
1563 * Create aliasing link.
1565 (void)PacketAliasRedirectProto(localAddr, remoteAddr, publicAddr,
1569 void SetupAddressRedirect (const char* parms)
1574 struct in_addr localAddr;
1575 struct in_addr publicAddr;
1577 struct alias_link *link;
1579 strcpy (buf, parms);
1581 * Extract local address.
1583 ptr = strtok (buf, " \t");
1585 errx (1, "redirect_address: missing local address");
1587 separator = strchr(ptr, ',');
1588 if (separator) { /* LSNAT redirection syntax. */
1589 localAddr.s_addr = INADDR_NONE;
1592 StrToAddr (ptr, &localAddr);
1596 * Extract public address.
1598 ptr = strtok (NULL, " \t");
1600 errx (1, "redirect_address: missing public address");
1602 StrToAddr (ptr, &publicAddr);
1603 link = PacketAliasRedirectAddr(localAddr, publicAddr);
1606 * Setup LSNAT server pool.
1608 if (serverPool != NULL && link != NULL) {
1609 ptr = strtok(serverPool, ",");
1610 while (ptr != NULL) {
1611 StrToAddr(ptr, &localAddr);
1612 PacketAliasAddServer(link, localAddr, htons(~0));
1613 ptr = strtok(NULL, ",");
1618 void StrToAddr (const char* str, struct in_addr* addr)
1622 if (inet_aton (str, addr))
1625 hp = gethostbyname (str);
1627 errx (1, "unknown host %s", str);
1629 memcpy (addr, hp->h_addr, sizeof (struct in_addr));
1632 u_short StrToPort (const char* str, const char* proto)
1638 port = strtol (str, &end, 10);
1640 return htons (port);
1642 sp = getservbyname (str, proto);
1644 errx (1, "unknown service %s/%s", str, proto);
1649 int StrToPortRange (const char* str, const char* proto, port_range *portRange)
1657 /* First see if this is a service, return corresponding port if so. */
1658 sp = getservbyname (str,proto);
1660 SETLOPORT(*portRange, ntohs(sp->s_port));
1661 SETNUMPORTS(*portRange, 1);
1665 /* Not a service, see if it's a single port or port range. */
1666 sep = strchr (str, '-');
1668 SETLOPORT(*portRange, strtol(str, &end, 10));
1671 SETNUMPORTS(*portRange, 1);
1675 /* Error in port range field. */
1676 errx (1, "unknown service %s/%s", str, proto);
1679 /* Port range, get the values and sanity check. */
1680 sscanf (str, "%hu-%hu", &loPort, &hiPort);
1681 SETLOPORT(*portRange, loPort);
1682 SETNUMPORTS(*portRange, 0); /* Error by default */
1683 if (loPort <= hiPort)
1684 SETNUMPORTS(*portRange, hiPort - loPort + 1);
1686 if (GETNUMPORTS(*portRange) == 0)
1687 errx (1, "invalid port range %s", str);
1693 int StrToProto (const char* str)
1695 if (!strcmp (str, "tcp"))
1698 if (!strcmp (str, "udp"))
1701 errx (1, "unknown protocol %s. Expected tcp or udp", str);
1704 int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange)
1708 ptr = strchr (str, ':');
1710 errx (1, "%s is missing port number", str);
1715 StrToAddr (str, addr);
1716 return StrToPortRange (ptr, proto, portRange);
1720 SetupPunchFW(const char *strValue)
1722 unsigned int base, num;
1724 if (sscanf(strValue, "%u:%u", &base, &num) != 2)
1725 errx(1, "punch_fw: basenumber:count parameter required");
1727 PacketAliasSetFWBase(base, num);
1728 (void)PacketAliasSetMode(PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);