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.8 2005/06/02 16:16:37 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;
108 static volatile sig_atomic_t running;
109 static volatile sig_atomic_t 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;
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 sa.sa_handler = InitiateShutdown;
295 sigemptyset(&sa.sa_mask);
296 sigaction(SIGTERM, &sa, NULL);
297 sa.sa_handler = RefreshAddr;
298 sigaction(SIGHUP, &sa, NULL);
300 * Set alias address if it has been given.
302 if (aliasAddr.s_addr != INADDR_NONE)
303 PacketAliasSetAddress (aliasAddr);
305 * We need largest descriptor number for select.
310 if (divertIn > fdMax)
313 if (divertOut > fdMax)
316 if (divertInOut > fdMax)
319 if (routeSock > fdMax)
324 if (divertInOut != -1 && !ifName) {
326 * When using only one socket, just call
327 * DoAliasing repeatedly to process packets.
329 DoAliasing (divertInOut, DONT_KNOW);
333 * Build read mask from socket descriptors to select.
337 * Check if new packets are available.
340 FD_SET (divertIn, &readMask);
343 FD_SET (divertOut, &readMask);
345 if (divertInOut != -1)
346 FD_SET (divertInOut, &readMask);
348 * Routing info is processed always.
351 FD_SET (routeSock, &readMask);
353 if (select (fdMax + 1,
362 Quit ("Select failed.");
366 if (FD_ISSET (divertIn, &readMask))
367 DoAliasing (divertIn, INPUT);
370 if (FD_ISSET (divertOut, &readMask))
371 DoAliasing (divertOut, OUTPUT);
373 if (divertInOut != -1)
374 if (FD_ISSET (divertInOut, &readMask))
375 DoAliasing (divertInOut, DONT_KNOW);
378 if (FD_ISSET (routeSock, &readMask))
379 HandleRoutingInfo (routeSock);
388 static void DaemonMode (void)
395 pidFile = fopen (PIDFILE, "w");
398 fprintf (pidFile, "%d\n", getpid ());
403 static void ParseArgs (int argc, char** argv)
408 int len; /* bounds checking */
410 for (arg = 1; arg < argc; arg++) {
415 warnx ("invalid option %s", opt);
422 while (arg < argc - 1) {
424 if (argv[arg + 1][0] == '-')
428 strncat (parmBuf, " ", sizeof(parmBuf) - (len + 1));
429 len += strlen(parmBuf + len);
433 strncat (parmBuf, argv[arg], sizeof(parmBuf) - (len + 1));
434 len += strlen(parmBuf + len);
438 ParseOption (opt + 1, (len ? parmBuf : NULL));
443 static void DoAliasing (int fd, int direction)
447 char buf[IP_MAXPACKET];
448 struct sockaddr_in addr;
455 if (assignAliasAddr) {
457 SetAliasAddressFromIfName (ifName);
461 * Get packet from socket.
463 addrSize = sizeof addr;
464 origBytes = recvfrom (fd,
468 (struct sockaddr*) &addr,
471 if (origBytes == -1) {
474 Warn ("read from divert socket failed");
479 * This is a IP packet.
481 ip = (struct ip*) buf;
482 if (direction == DONT_KNOW) {
483 if (addr.sin_addr.s_addr == INADDR_ANY)
491 * Print packet direction and protocol type.
493 printf (direction == OUTPUT ? "Out " : "In ");
509 printf ("[%d] ", ip->ip_p);
518 if (direction == OUTPUT) {
520 * Outgoing packets. Do aliasing.
522 PacketAliasOut (buf, IP_MAXPACKET);
529 status = PacketAliasIn (buf, IP_MAXPACKET);
530 if (status == PKT_ALIAS_IGNORED &&
531 dropIgnoredIncoming) {
534 printf (" dropped.\n");
537 SyslogPacket (ip, LOG_WARNING, "denied");
543 * Length might have changed during aliasing.
545 bytes = ntohs (ip->ip_len);
547 * Update alias overhead size for outgoing packets.
549 if (direction == OUTPUT &&
550 bytes - origBytes > aliasOverhead)
551 aliasOverhead = bytes - origBytes;
556 * Print addresses after aliasing.
558 printf (" aliased to\n");
565 * Put packet back for processing.
571 (struct sockaddr*) &addr,
574 if (wrote != bytes) {
576 if (errno == EMSGSIZE) {
578 if (direction == OUTPUT &&
580 SendNeedFragIcmp (icmpSock,
582 ifMTU - aliasOverhead);
584 else if (errno == EACCES && logIpfwDenied) {
586 sprintf (msgBuf, "failed to write packet back");
592 static void HandleRoutingInfo (int fd)
595 struct if_msghdr ifMsg;
597 * Get packet from socket.
599 bytes = read (fd, &ifMsg, sizeof ifMsg);
602 Warn ("read from routing socket failed");
606 if (ifMsg.ifm_version != RTM_VERSION) {
608 Warn ("unexpected packet read from routing socket");
613 printf ("Routing message %#x received.\n", ifMsg.ifm_type);
615 if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO) &&
616 ifMsg.ifm_index == ifIndex) {
618 printf("Interface address/MTU has probably changed.\n");
623 static void PrintPacket (struct ip* ip)
625 printf ("%s", FormatPacket (ip));
628 static void SyslogPacket (struct ip* ip, int priority, const char *label)
630 syslog (priority, "%s %s", label, FormatPacket (ip));
633 static char* FormatPacket (struct ip* ip)
635 static char buf[256];
636 struct tcphdr* tcphdr;
637 struct udphdr* udphdr;
638 struct icmp* icmphdr;
642 strcpy (src, inet_ntoa (ip->ip_src));
643 strcpy (dst, inet_ntoa (ip->ip_dst));
647 tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2));
648 sprintf (buf, "[TCP] %s:%d -> %s:%d",
650 ntohs (tcphdr->th_sport),
652 ntohs (tcphdr->th_dport));
656 udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2));
657 sprintf (buf, "[UDP] %s:%d -> %s:%d",
659 ntohs (udphdr->uh_sport),
661 ntohs (udphdr->uh_dport));
665 icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2));
666 sprintf (buf, "[ICMP] %s -> %s %u(%u)",
674 sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst);
682 SetAliasAddressFromIfName(const char *ifn)
686 char *buf, *lim, *next;
687 struct if_msghdr *ifm;
688 struct ifa_msghdr *ifam;
689 struct sockaddr_dl *s_dl;
690 struct sockaddr_in *s_in;
695 mib[3] = AF_INET; /* Only IP addresses please */
696 mib[4] = NET_RT_IFLIST;
697 mib[5] = 0; /* ifIndex??? */
699 * Get interface data.
701 if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
702 err(1, "iflist-sysctl-estimate");
703 if ((buf = malloc(needed)) == NULL)
704 errx(1, "malloc failed");
705 if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
706 err(1, "iflist-sysctl-get");
709 * Loop through interfaces until one with
710 * given name is found. This is done to
711 * find correct interface index for routing
712 * message processing.
717 ifm = (struct if_msghdr *)next;
718 next += ifm->ifm_msglen;
719 if (ifm->ifm_version != RTM_VERSION) {
721 warnx("routing message version %d "
722 "not understood", ifm->ifm_version);
725 if (ifm->ifm_type == RTM_IFINFO) {
726 s_dl = (struct sockaddr_dl *)(ifm + 1);
727 if (strlen(ifn) == s_dl->sdl_nlen &&
728 strncmp(ifn, s_dl->sdl_data, s_dl->sdl_nlen) == 0) {
729 ifIndex = ifm->ifm_index;
730 ifMTU = ifm->ifm_data.ifi_mtu;
736 errx(1, "unknown interface name %s", ifn);
738 * Get interface address.
742 ifam = (struct ifa_msghdr *)next;
743 next += ifam->ifam_msglen;
744 if (ifam->ifam_version != RTM_VERSION) {
746 warnx("routing message version %d "
747 "not understood", ifam->ifam_version);
750 if (ifam->ifam_type != RTM_NEWADDR)
752 if (ifam->ifam_addrs & RTA_IFA) {
754 char *cp = (char *)(ifam + 1);
757 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
758 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
760 for (i = 1; i < RTA_IFA; i <<= 1)
761 if (ifam->ifam_addrs & i)
762 ADVANCE(cp, (struct sockaddr *)cp);
763 if (((struct sockaddr *)cp)->sa_family == AF_INET) {
764 s_in = (struct sockaddr_in *)cp;
770 errx(1, "%s: cannot get interface address", ifn);
772 PacketAliasSetAddress(s_in->sin_addr);
773 syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes",
774 inet_ntoa(s_in->sin_addr), ifMTU);
779 void Quit (const char* msg)
785 void Warn (const char* msg)
788 syslog (LOG_ALERT, "%s (%m)", msg);
793 static void RefreshAddr (int sig __unused)
799 static void InitiateShutdown (int sig __unused)
803 * Start timer to allow kernel gracefully
804 * shutdown existing connections when system
807 sa.sa_handler = Shutdown;
809 sigemptyset(&sa.sa_mask);
810 sigaction(SIGALRM, &sa, NULL);
814 static void Shutdown (int sig __unused)
820 * Different options recognized by this program.
856 * Option information structure (used by ParseOption).
864 const char* parmDescription;
865 const char* description;
867 const char* shortName;
871 * Table of known options.
874 static struct OptionInfo optionTable[] = {
877 PKT_ALIAS_UNREGISTERED_ONLY,
880 "alias only unregistered addresses",
893 PKT_ALIAS_PROXY_ONLY,
904 "operate in reverse mode",
909 PKT_ALIAS_DENY_INCOMING,
912 "allow incoming connections",
917 PKT_ALIAS_USE_SOCKETS,
920 "use sockets to inhibit port conflict",
925 PKT_ALIAS_SAME_PORTS,
928 "try to keep original port numbers for connections",
936 "verbose mode, dump packet information",
944 "dynamic mode, automatically detect interface address changes",
951 "number|service_name",
952 "set port for incoming packets",
959 "number|service_name",
960 "set port for outgoing packets",
967 "number|service_name",
968 "set port (defaults to natd/divert)",
976 "address to use for aliasing",
984 "address to use for incoming sessions",
992 "take aliasing address from interface",
999 "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
1001 "add transparent proxying / destination NAT",
1008 "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
1009 " [remote_addr[:remote_port_range]]",
1010 "redirect a port (or ports) for incoming traffic",
1017 "proto local_addr [public_addr] [remote_addr]",
1018 "redirect packets of a given proto",
1025 "local_addr[,...] public_addr",
1026 "define mapping between local and public addresses",
1034 "read options from configuration file",
1042 "enable logging of denied incoming packets",
1050 "name of syslog facility to use for logging",
1058 "punch holes in the firewall for incoming FTP/IRC DCC connections",
1066 "log packets converted by natd, but denied by ipfw",
1071 static void ParseOption (const char* option, const char* parms)
1074 struct OptionInfo* info;
1079 const char* strValue;
1080 struct in_addr addrValue;
1083 CODE* fac_record = NULL;
1085 * Find option from table.
1087 max = sizeof (optionTable) / sizeof (struct OptionInfo);
1088 for (i = 0, info = optionTable; i < max; i++, info++) {
1090 if (!strcmp (info->name, option))
1093 if (info->shortName)
1094 if (!strcmp (info->shortName, option))
1100 warnx ("unknown option %s", option);
1111 switch (info->parm) {
1116 if (!strcmp (parms, "yes"))
1119 if (!strcmp (parms, "no"))
1122 errx (1, "%s needs yes/no parameter", option);
1127 errx (1, "%s needs service name or "
1128 "port number parameter",
1131 uNumValue = StrToPort (parms, "divert");
1136 numValue = strtol (parms, &end, 10);
1141 errx (1, "%s needs numeric parameter", option);
1147 errx (1, "%s needs parameter", option);
1152 errx (1, "%s does not take parameters", option);
1157 errx (1, "%s needs address/host parameter", option);
1159 StrToAddr (parms, &addrValue);
1163 switch (info->type) {
1164 case PacketAliasOption:
1166 aliasValue = yesNoValue ? info->packetAliasOpt : 0;
1167 PacketAliasSetMode (aliasValue, info->packetAliasOpt);
1171 verbose = yesNoValue;
1175 dynamicMode = yesNoValue;
1183 outPort = uNumValue;
1187 inOutPort = uNumValue;
1191 memcpy (&aliasAddr, &addrValue, sizeof (struct in_addr));
1195 PacketAliasSetTarget(addrValue);
1199 SetupPortRedirect (strValue);
1203 SetupProtoRedirect(strValue);
1206 case RedirectAddress:
1207 SetupAddressRedirect (strValue);
1211 PacketAliasProxyRule (strValue);
1218 ifName = strdup (strValue);
1222 ReadConfigFile (strValue);
1226 logDropped = yesNoValue;
1231 fac_record = facilitynames;
1232 while (fac_record->c_name != NULL) {
1234 if (!strcmp (fac_record->c_name, strValue)) {
1236 logFacility = fac_record->c_val;
1244 if(fac_record->c_name == NULL)
1245 errx(1, "Unknown log facility name: %s", strValue);
1250 SetupPunchFW(strValue);
1254 logIpfwDenied = yesNoValue;;
1259 void ReadConfigFile (const char* fileName)
1267 file = fopen (fileName, "r");
1269 err(1, "cannot open config file %s", fileName);
1271 while ((buf = fgetln(file, &len)) != NULL) {
1272 if (buf[len - 1] == '\n')
1273 buf[len - 1] = '\0';
1275 errx(1, "config file format error: "
1276 "last line should end with newline");
1279 * Check for comments, strip off trailing spaces.
1281 if ((ptr = strchr(buf, '#')))
1283 for (ptr = buf; isspace(*ptr); ++ptr)
1287 for (p = strchr(buf, '\0'); isspace(*--p);)
1292 * Extract option name.
1295 while (*ptr && !isspace (*ptr))
1304 * Skip white space between name and parms.
1306 while (*ptr && isspace (*ptr))
1309 ParseOption (option, *ptr ? ptr : NULL);
1315 static void Usage (void)
1319 struct OptionInfo* info;
1321 fprintf (stderr, "Recognized options:\n\n");
1323 max = sizeof (optionTable) / sizeof (struct OptionInfo);
1324 for (i = 0, info = optionTable; i < max; i++, info++) {
1326 fprintf (stderr, "-%-20s %s\n", info->name,
1327 info->parmDescription);
1329 if (info->shortName)
1330 fprintf (stderr, "-%-20s %s\n", info->shortName,
1331 info->parmDescription);
1333 fprintf (stderr, " %s\n\n", info->description);
1339 void SetupPortRedirect (const char* parms)
1344 struct in_addr localAddr;
1345 struct in_addr publicAddr;
1346 struct in_addr remoteAddr;
1347 port_range portRange;
1348 u_short localPort = 0;
1349 u_short publicPort = 0;
1350 u_short remotePort = 0;
1351 u_short numLocalPorts = 0;
1352 u_short numPublicPorts = 0;
1353 u_short numRemotePorts = 0;
1358 struct alias_link *alink = NULL;
1360 strcpy (buf, parms);
1364 protoName = strtok (buf, " \t");
1366 errx (1, "redirect_port: missing protocol");
1368 proto = StrToProto (protoName);
1370 * Extract local address.
1372 ptr = strtok (NULL, " \t");
1374 errx (1, "redirect_port: missing local address");
1376 separator = strchr(ptr, ',');
1377 if (separator) { /* LSNAT redirection syntax. */
1378 localAddr.s_addr = INADDR_NONE;
1383 if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 )
1384 errx (1, "redirect_port: invalid local port range");
1386 localPort = GETLOPORT(portRange);
1387 numLocalPorts = GETNUMPORTS(portRange);
1392 * Extract public port and optionally address.
1394 ptr = strtok (NULL, " \t");
1396 errx (1, "redirect_port: missing public port");
1398 separator = strchr (ptr, ':');
1400 if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 )
1401 errx (1, "redirect_port: invalid public port range");
1404 publicAddr.s_addr = INADDR_ANY;
1405 if (StrToPortRange (ptr, protoName, &portRange) != 0)
1406 errx (1, "redirect_port: invalid public port range");
1409 publicPort = GETLOPORT(portRange);
1410 numPublicPorts = GETNUMPORTS(portRange);
1413 * Extract remote address and optionally port.
1415 ptr = strtok (NULL, " \t");
1417 separator = strchr (ptr, ':');
1419 if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0)
1420 errx (1, "redirect_port: invalid remote port range");
1422 SETLOPORT(portRange, 0);
1423 SETNUMPORTS(portRange, 1);
1424 StrToAddr (ptr, &remoteAddr);
1428 SETLOPORT(portRange, 0);
1429 SETNUMPORTS(portRange, 1);
1430 remoteAddr.s_addr = INADDR_ANY;
1433 remotePort = GETLOPORT(portRange);
1434 numRemotePorts = GETNUMPORTS(portRange);
1437 * Make sure port ranges match up, then add the redirect ports.
1439 if (numLocalPorts != numPublicPorts)
1440 errx (1, "redirect_port: port ranges must be equal in size");
1442 /* Remote port range is allowed to be '0' which means all ports. */
1443 if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0))
1444 errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
1446 for (i = 0 ; i < numPublicPorts ; ++i) {
1447 /* If remotePort is all ports, set it to 0. */
1448 u_short remotePortCopy = remotePort + i;
1449 if (numRemotePorts == 1 && remotePort == 0)
1452 alink = PacketAliasRedirectPort(localAddr,
1453 htons(localPort + i),
1455 htons(remotePortCopy),
1457 htons(publicPort + i),
1462 * Setup LSNAT server pool.
1464 if (serverPool != NULL && alink != NULL) {
1465 ptr = strtok(serverPool, ",");
1466 while (ptr != NULL) {
1467 if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0)
1468 errx(1, "redirect_port: invalid local port range");
1470 localPort = GETLOPORT(portRange);
1471 if (GETNUMPORTS(portRange) != 1)
1472 errx(1, "redirect_port: local port must be single in this context");
1473 PacketAliasAddServer(alink, localAddr, htons(localPort));
1474 ptr = strtok(NULL, ",");
1480 SetupProtoRedirect(const char* parms)
1484 struct in_addr localAddr;
1485 struct in_addr publicAddr;
1486 struct in_addr remoteAddr;
1489 struct protoent *protoent;
1491 strcpy (buf, parms);
1495 protoName = strtok(buf, " \t");
1497 errx(1, "redirect_proto: missing protocol");
1499 protoent = getprotobyname(protoName);
1500 if (protoent == NULL)
1501 errx(1, "redirect_proto: unknown protocol %s", protoName);
1503 proto = protoent->p_proto;
1505 * Extract local address.
1507 ptr = strtok(NULL, " \t");
1509 errx(1, "redirect_proto: missing local address");
1511 StrToAddr(ptr, &localAddr);
1513 * Extract optional public address.
1515 ptr = strtok(NULL, " \t");
1517 StrToAddr(ptr, &publicAddr);
1519 publicAddr.s_addr = INADDR_ANY;
1521 * Extract optional remote address.
1523 ptr = strtok(NULL, " \t");
1525 StrToAddr(ptr, &remoteAddr);
1527 remoteAddr.s_addr = INADDR_ANY;
1529 * Create aliasing link.
1531 PacketAliasRedirectProto(localAddr, remoteAddr, publicAddr, proto);
1534 void SetupAddressRedirect (const char* parms)
1539 struct in_addr localAddr;
1540 struct in_addr publicAddr;
1542 struct alias_link *alink;
1544 strcpy (buf, parms);
1546 * Extract local address.
1548 ptr = strtok (buf, " \t");
1550 errx (1, "redirect_address: missing local address");
1552 separator = strchr(ptr, ',');
1553 if (separator) { /* LSNAT redirection syntax. */
1554 localAddr.s_addr = INADDR_NONE;
1557 StrToAddr (ptr, &localAddr);
1561 * Extract public address.
1563 ptr = strtok (NULL, " \t");
1565 errx (1, "redirect_address: missing public address");
1567 StrToAddr (ptr, &publicAddr);
1568 alink = PacketAliasRedirectAddr(localAddr, publicAddr);
1571 * Setup LSNAT server pool.
1573 if (serverPool != NULL && alink != NULL) {
1574 ptr = strtok(serverPool, ",");
1575 while (ptr != NULL) {
1576 StrToAddr(ptr, &localAddr);
1577 PacketAliasAddServer(alink, localAddr, htons(~0));
1578 ptr = strtok(NULL, ",");
1583 void StrToAddr (const char* str, struct in_addr* addr)
1587 if (inet_aton (str, addr))
1590 hp = gethostbyname (str);
1592 errx (1, "unknown host %s", str);
1594 memcpy (addr, hp->h_addr, sizeof (struct in_addr));
1597 u_short StrToPort (const char* str, const char* proto)
1603 port = strtol (str, &end, 10);
1605 return htons (port);
1607 sp = getservbyname (str, proto);
1609 errx (1, "unknown service %s/%s", str, proto);
1614 int StrToPortRange (const char* str, const char* proto, port_range *portRange)
1622 /* First see if this is a service, return corresponding port if so. */
1623 sp = getservbyname (str,proto);
1625 SETLOPORT(*portRange, ntohs(sp->s_port));
1626 SETNUMPORTS(*portRange, 1);
1630 /* Not a service, see if it's a single port or port range. */
1631 sep = strchr (str, '-');
1633 SETLOPORT(*portRange, strtol(str, &end, 10));
1636 SETNUMPORTS(*portRange, 1);
1640 /* Error in port range field. */
1641 errx (1, "unknown service %s/%s", str, proto);
1644 /* Port range, get the values and sanity check. */
1645 sscanf (str, "%hu-%hu", &loPort, &hiPort);
1646 SETLOPORT(*portRange, loPort);
1647 SETNUMPORTS(*portRange, 0); /* Error by default */
1648 if (loPort <= hiPort)
1649 SETNUMPORTS(*portRange, hiPort - loPort + 1);
1651 if (GETNUMPORTS(*portRange) == 0)
1652 errx (1, "invalid port range %s", str);
1658 int StrToProto (const char* str)
1660 if (!strcmp (str, "tcp"))
1663 if (!strcmp (str, "udp"))
1666 errx (1, "unknown protocol %s. Expected tcp or udp", str);
1669 int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange)
1673 ptr = strchr (str, ':');
1675 errx (1, "%s is missing port number", str);
1680 StrToAddr (str, addr);
1681 return StrToPortRange (ptr, proto, portRange);
1685 SetupPunchFW(const char *strValue)
1687 unsigned int base, num;
1689 if (sscanf(strValue, "%u:%u", &base, &num) != 2)
1690 errx(1, "punch_fw: basenumber:count parameter required");
1692 PacketAliasSetFWBase(base, num);
1693 PacketAliasSetMode(PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);