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.10 2005/11/06 12:44:12 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, int);
79 static void DaemonMode(void);
80 static void HandleRoutingInfo(int);
81 static void Usage(void);
82 static char* FormatPacket(struct ip
*);
83 static void PrintPacket(struct ip
*);
84 static void SyslogPacket(struct ip
*, int, const char *);
85 static void SetAliasAddressFromIfName(const char *);
86 static void InitiateShutdown(int);
87 static void Shutdown(int);
88 static void RefreshAddr(int);
89 static void ParseOption(const char *, const char *);
90 static void ReadConfigFile(const char *);
91 static void SetupPortRedirect(const char *);
92 static void SetupProtoRedirect(const char *);
93 static void SetupAddressRedirect(const char *);
94 static void StrToAddr(const char *, struct in_addr
*);
95 static u_short
StrToPort(const char *, const char *);
96 static int StrToPortRange(const char *, const char *, port_range
*);
97 static int StrToProto(const char *);
98 static int StrToAddrAndPortRange(const char *, struct in_addr
*, char *, port_range
*);
99 static void ParseArgs(int, char **);
100 static void SetupPunchFW(const char *);
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
;
126 main(int argc
, char **argv
)
132 struct sockaddr_in addr
;
137 * Initialize packet aliasing software.
138 * Done already here to be able to alter option bits
139 * during command line and configuration file processing.
154 aliasAddr
.s_addr
= INADDR_NONE
;
158 logFacility
= LOG_DAEMON
;
161 ParseArgs(argc
, argv
);
163 * Log ipfw(8) denied packets by default in verbose mode.
165 if (logIpfwDenied
== -1)
166 logIpfwDenied
= verbose
;
168 * Open syslog channel.
170 openlog("natd", LOG_CONS
| LOG_PID
| (verbose
? LOG_PERROR
: 0),
173 * Check that valid aliasing address has been given.
175 if (aliasAddr
.s_addr
== INADDR_NONE
&& ifName
== NULL
)
176 errx(1, "aliasing address not given");
178 if (aliasAddr
.s_addr
!= INADDR_NONE
&& ifName
!= NULL
)
179 errx(1, "both alias address and interface "
180 "name are not allowed");
182 * Check that valid port number is known.
184 if (inPort
!= 0 || outPort
!= 0)
185 if (inPort
== 0 || outPort
== 0)
186 errx(1, "both input and output ports are required");
188 if (inPort
== 0 && outPort
== 0 && inOutPort
== 0)
189 ParseOption("port", DEFAULT_SERVICE
);
192 * Check if ignored packets should be dropped.
194 dropIgnoredIncoming
= PacketAliasSetMode(0, 0);
195 dropIgnoredIncoming
&= PKT_ALIAS_DENY_INCOMING
;
197 * Create divert sockets. Use only one socket if -p was specified
198 * on command line. Otherwise, create separate sockets for
199 * 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.");
221 divertIn
= socket(PF_INET
, SOCK_RAW
, IPPROTO_DIVERT
);
223 Quit("Unable to create incoming divert socket.");
225 divertOut
= socket(PF_INET
, SOCK_RAW
, IPPROTO_DIVERT
);
227 Quit("Unable to create outgoing divert socket.");
232 * Bind divert sockets.
235 addr
.sin_family
= AF_INET
;
236 addr
.sin_addr
.s_addr
= INADDR_ANY
;
237 addr
.sin_port
= inPort
;
240 (struct sockaddr
*)&addr
,
242 Quit("Unable to bind incoming divert socket.");
244 addr
.sin_family
= AF_INET
;
245 addr
.sin_addr
.s_addr
= INADDR_ANY
;
246 addr
.sin_port
= outPort
;
249 (struct sockaddr
*)&addr
,
251 Quit("Unable to bind outgoing divert socket.");
254 * Create routing socket if interface name specified and in dynamic mode.
259 routeSock
= socket(PF_ROUTE
, SOCK_RAW
, 0);
261 Quit("Unable to create routing info socket.");
265 SetAliasAddressFromIfName(ifName
);
268 * Create socket for sending ICMP messages.
270 icmpSock
= socket(AF_INET
, SOCK_RAW
, IPPROTO_ICMP
);
272 Quit("Unable to create ICMP socket.");
275 * And disable reads for the socket, otherwise it slowly fills
276 * up with received icmps which we do not use.
278 shutdown(icmpSock
, SHUT_RD
);
281 * Become a daemon unless verbose mode was requested.
286 * Catch signals to manage shutdown and
287 * refresh of interface address.
289 sa
.sa_handler
= InitiateShutdown
;
291 sigemptyset(&sa
.sa_mask
);
292 sigaction(SIGTERM
, &sa
, NULL
);
293 sa
.sa_handler
= RefreshAddr
;
294 sigaction(SIGHUP
, &sa
, NULL
);
296 * Set alias address if it has been given.
298 if (aliasAddr
.s_addr
!= INADDR_NONE
)
299 PacketAliasSetAddress(aliasAddr
);
301 * We need largest descriptor number for select.
306 if (divertIn
> fdMax
)
309 if (divertOut
> fdMax
)
312 if (divertInOut
> fdMax
)
315 if (routeSock
> fdMax
)
319 if (divertInOut
!= -1 && !ifName
) {
321 * When using only one socket, just call
322 * DoAliasing repeatedly to process packets.
324 DoAliasing(divertInOut
, DONT_KNOW
);
328 * Build read mask from socket descriptors to select.
332 * Check if new packets are available.
335 FD_SET(divertIn
, &readMask
);
338 FD_SET(divertOut
, &readMask
);
340 if (divertInOut
!= -1)
341 FD_SET(divertInOut
, &readMask
);
343 * Routing info is processed always.
346 FD_SET(routeSock
, &readMask
);
348 if (select(fdMax
+ 1,
356 Quit("Select failed.");
360 if (FD_ISSET(divertIn
, &readMask
))
361 DoAliasing(divertIn
, INPUT
);
364 if (FD_ISSET(divertOut
, &readMask
))
365 DoAliasing(divertOut
, OUTPUT
);
367 if (divertInOut
!= -1)
368 if (FD_ISSET(divertInOut
, &readMask
))
369 DoAliasing(divertInOut
, DONT_KNOW
);
372 if (FD_ISSET(routeSock
, &readMask
))
373 HandleRoutingInfo(routeSock
);
390 pidFile
= fopen(PIDFILE
, "w");
392 fprintf(pidFile
, "%d\n", getpid());
398 ParseArgs(int argc
, char **argv
)
403 int len
; /* bounds checking */
405 for (arg
= 1; arg
< argc
; arg
++) {
408 warnx("invalid option %s", opt
);
415 while (arg
< argc
- 1) {
416 if (argv
[arg
+ 1][0] == '-')
420 strncat(parmBuf
, " ", sizeof(parmBuf
) - (len
+ 1));
421 len
+= strlen(parmBuf
+ len
);
425 strncat(parmBuf
, argv
[arg
], sizeof(parmBuf
) - (len
+ 1));
426 len
+= strlen(parmBuf
+ len
);
430 ParseOption(opt
+ 1, (len
? parmBuf
: NULL
));
436 DoAliasing(int fd
, int direction
)
440 char buf
[IP_MAXPACKET
];
441 struct sockaddr_in addr
;
448 if (assignAliasAddr
) {
449 SetAliasAddressFromIfName(ifName
);
453 * Get packet from socket.
455 addrSize
= sizeof addr
;
456 origBytes
= recvfrom(fd
,
460 (struct sockaddr
*)&addr
,
463 if (origBytes
== -1) {
465 Warn("read from divert socket failed");
470 * This is a IP packet.
472 ip
= (struct ip
*)buf
;
473 if (direction
== DONT_KNOW
) {
474 if (addr
.sin_addr
.s_addr
== INADDR_ANY
)
482 * Print packet direction and protocol type.
484 printf(direction
== OUTPUT
? "Out " : "In ");
500 printf("[%d] ", ip
->ip_p
);
509 if (direction
== OUTPUT
) {
511 * Outgoing packets. Do aliasing.
513 PacketAliasOut(buf
, IP_MAXPACKET
);
518 status
= PacketAliasIn(buf
, IP_MAXPACKET
);
519 if (status
== PKT_ALIAS_IGNORED
&&
520 dropIgnoredIncoming
) {
522 printf(" dropped.\n");
525 SyslogPacket(ip
, LOG_WARNING
, "denied");
531 * Length might have changed during aliasing.
533 bytes
= ntohs(ip
->ip_len
);
535 * Update alias overhead size for outgoing packets.
537 if (direction
== OUTPUT
&&
538 bytes
- origBytes
> aliasOverhead
)
539 aliasOverhead
= bytes
- origBytes
;
543 * Print addresses after aliasing.
545 printf(" aliased to\n");
552 * Put packet back for processing.
558 (struct sockaddr
*)&addr
,
561 if (wrote
!= bytes
) {
562 if (errno
== EMSGSIZE
) {
563 if (direction
== OUTPUT
&&
565 SendNeedFragIcmp(icmpSock
,
567 ifMTU
- aliasOverhead
);
568 } else if (errno
== EACCES
&& logIpfwDenied
) {
569 sprintf(msgBuf
, "failed to write packet back");
576 HandleRoutingInfo(int fd
)
579 struct if_msghdr ifMsg
;
581 * Get packet from socket.
583 bytes
= read(fd
, &ifMsg
, sizeof ifMsg
);
585 Warn("read from routing socket failed");
589 if (ifMsg
.ifm_version
!= RTM_VERSION
) {
590 Warn("unexpected packet read from routing socket");
595 printf("Routing message %#x received.\n", ifMsg
.ifm_type
);
597 if ((ifMsg
.ifm_type
== RTM_NEWADDR
|| ifMsg
.ifm_type
== RTM_IFINFO
) &&
598 ifMsg
.ifm_index
== ifIndex
) {
600 printf("Interface address/MTU has probably changed.\n");
606 PrintPacket(struct ip
*ip
)
608 printf("%s", FormatPacket(ip
));
612 SyslogPacket(struct ip
*ip
, int priority
, const char *label
)
614 syslog(priority
, "%s %s", label
, FormatPacket(ip
));
618 FormatPacket(struct ip
*ip
)
620 static char buf
[256];
621 struct tcphdr
* tcphdr
;
622 struct udphdr
* udphdr
;
623 struct icmp
* icmphdr
;
627 strcpy(src
, inet_ntoa(ip
->ip_src
));
628 strcpy(dst
, inet_ntoa(ip
->ip_dst
));
632 tcphdr
= (struct tcphdr
*)((char *)ip
+ (ip
->ip_hl
<< 2));
633 sprintf(buf
, "[TCP] %s:%d -> %s:%d",
635 ntohs(tcphdr
->th_sport
),
637 ntohs(tcphdr
->th_dport
));
641 udphdr
= (struct udphdr
*)((char *)ip
+ (ip
->ip_hl
<< 2));
642 sprintf(buf
, "[UDP] %s:%d -> %s:%d",
644 ntohs(udphdr
->uh_sport
),
646 ntohs(udphdr
->uh_dport
));
650 icmphdr
= (struct icmp
*)((char *)ip
+ (ip
->ip_hl
<< 2));
651 sprintf(buf
, "[ICMP] %s -> %s %u(%u)",
659 sprintf(buf
, "[%d] %s -> %s ", ip
->ip_p
, src
, dst
);
667 SetAliasAddressFromIfName(const char *ifn
)
671 char *buf
, *lim
, *next
;
672 struct if_msghdr
*ifm
;
673 struct ifa_msghdr
*ifam
;
674 struct sockaddr_dl
*s_dl
;
675 struct sockaddr_in
*s_in
;
680 mib
[3] = AF_INET
; /* Only IP addresses please */
681 mib
[4] = NET_RT_IFLIST
;
682 mib
[5] = 0; /* ifIndex??? */
684 * Get interface data.
686 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) == -1)
687 err(1, "iflist-sysctl-estimate");
688 if ((buf
= malloc(needed
)) == NULL
)
689 errx(1, "malloc failed");
690 if (sysctl(mib
, 6, buf
, &needed
, NULL
, 0) == -1)
691 err(1, "iflist-sysctl-get");
694 * Loop through interfaces until one with
695 * given name is found. This is done to
696 * find correct interface index for routing
697 * message processing.
702 ifm
= (struct if_msghdr
*)next
;
703 next
+= ifm
->ifm_msglen
;
704 if (ifm
->ifm_version
!= RTM_VERSION
) {
706 warnx("routing message version %d "
707 "not understood", ifm
->ifm_version
);
710 if (ifm
->ifm_type
== RTM_IFINFO
) {
711 s_dl
= (struct sockaddr_dl
*)(ifm
+ 1);
712 if (strlen(ifn
) == s_dl
->sdl_nlen
&&
713 strncmp(ifn
, s_dl
->sdl_data
, s_dl
->sdl_nlen
) == 0) {
714 ifIndex
= ifm
->ifm_index
;
715 ifMTU
= ifm
->ifm_data
.ifi_mtu
;
721 errx(1, "unknown interface name %s", ifn
);
723 * Get interface address.
727 ifam
= (struct ifa_msghdr
*)next
;
728 next
+= ifam
->ifam_msglen
;
729 if (ifam
->ifam_version
!= RTM_VERSION
) {
731 warnx("routing message version %d "
732 "not understood", ifam
->ifam_version
);
735 if (ifam
->ifam_type
!= RTM_NEWADDR
)
737 if (ifam
->ifam_addrs
& RTA_IFA
) {
739 char *cp
= (char *)(ifam
+ 1);
742 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
743 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
745 for (i
= 1; i
< RTA_IFA
; i
<<= 1)
746 if (ifam
->ifam_addrs
& i
)
747 ADVANCE(cp
, (struct sockaddr
*)cp
);
748 if (((struct sockaddr
*)cp
)->sa_family
== AF_INET
) {
749 s_in
= (struct sockaddr_in
*)cp
;
755 errx(1, "%s: cannot get interface address", ifn
);
757 PacketAliasSetAddress(s_in
->sin_addr
);
758 syslog(LOG_INFO
, "Aliasing to %s, mtu %d bytes",
759 inet_ntoa(s_in
->sin_addr
), ifMTU
);
765 Quit(const char *msg
)
772 Warn(const char *msg
)
775 syslog(LOG_ALERT
, "%s (%m)", msg
);
781 RefreshAddr(int sig __unused
)
788 InitiateShutdown(int sig __unused
)
792 * Start timer to allow kernel gracefully
793 * shutdown existing connections when system
796 sa
.sa_handler
= Shutdown
;
798 sigemptyset(&sa
.sa_mask
);
799 sigaction(SIGALRM
, &sa
, NULL
);
804 Shutdown(int sig __unused
)
810 * Different options recognized by this program.
844 * Option information structure (used by ParseOption).
851 const char* parmDescription
;
852 const char* description
;
854 const char* shortName
;
858 * Table of known options.
861 static struct OptionInfo optionTable
[] = {
863 PKT_ALIAS_UNREGISTERED_ONLY
,
866 "alias only unregistered addresses",
879 PKT_ALIAS_PROXY_ONLY
,
890 "operate in reverse mode",
895 PKT_ALIAS_DENY_INCOMING
,
898 "allow incoming connections",
903 PKT_ALIAS_USE_SOCKETS
,
906 "use sockets to inhibit port conflict",
911 PKT_ALIAS_SAME_PORTS
,
914 "try to keep original port numbers for connections",
922 "verbose mode, dump packet information",
930 "dynamic mode, automatically detect interface address changes",
937 "number|service_name",
938 "set port for incoming packets",
945 "number|service_name",
946 "set port for outgoing packets",
953 "number|service_name",
954 "set port (defaults to natd/divert)",
962 "address to use for aliasing",
970 "address to use for incoming sessions",
978 "take aliasing address from interface",
985 "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
987 "add transparent proxying / destination NAT",
994 "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
995 " [remote_addr[:remote_port_range]]",
996 "redirect a port (or ports) for incoming traffic",
1003 "proto local_addr [public_addr] [remote_addr]",
1004 "redirect packets of a given proto",
1011 "local_addr[,...] public_addr",
1012 "define mapping between local and public addresses",
1020 "read options from configuration file",
1028 "enable logging of denied incoming packets",
1036 "name of syslog facility to use for logging",
1044 "punch holes in the firewall for incoming FTP/IRC DCC connections",
1052 "log packets converted by natd, but denied by ipfw",
1058 ParseOption(const char *option
, const char *parms
)
1061 struct OptionInfo
* info
;
1066 const char* strValue
;
1067 struct in_addr addrValue
;
1070 CODE
* fac_record
= NULL
;
1072 * Find option from table.
1074 max
= sizeof(optionTable
) / sizeof(struct OptionInfo
);
1075 for (i
= 0, info
= optionTable
; i
< max
; i
++, info
++) {
1076 if (!strcmp(info
->name
, option
))
1079 if (info
->shortName
)
1080 if (!strcmp(info
->shortName
, option
))
1085 warnx("unknown option %s", option
);
1096 switch (info
->parm
) {
1101 if (!strcmp(parms
, "yes"))
1104 if (!strcmp(parms
, "no"))
1107 errx(1, "%s needs yes/no parameter", option
);
1112 errx(1, "%s needs service name or "
1113 "port number parameter",
1116 uNumValue
= StrToPort(parms
, "divert");
1121 numValue
= strtol(parms
, &end
, 10);
1126 errx(1, "%s needs numeric parameter", option
);
1132 errx(1, "%s needs parameter", option
);
1137 errx(1, "%s does not take parameters", option
);
1142 errx(1, "%s needs address/host parameter", option
);
1144 StrToAddr(parms
, &addrValue
);
1148 switch (info
->type
) {
1149 case PacketAliasOption
:
1151 aliasValue
= yesNoValue
? info
->packetAliasOpt
: 0;
1152 PacketAliasSetMode(aliasValue
, info
->packetAliasOpt
);
1156 verbose
= yesNoValue
;
1160 dynamicMode
= yesNoValue
;
1168 outPort
= uNumValue
;
1172 inOutPort
= uNumValue
;
1176 memcpy(&aliasAddr
, &addrValue
, sizeof(struct in_addr
));
1180 PacketAliasSetTarget(addrValue
);
1184 SetupPortRedirect(strValue
);
1188 SetupProtoRedirect(strValue
);
1191 case RedirectAddress
:
1192 SetupAddressRedirect(strValue
);
1196 PacketAliasProxyRule(strValue
);
1203 ifName
= strdup(strValue
);
1207 ReadConfigFile(strValue
);
1211 logDropped
= yesNoValue
;
1216 fac_record
= facilitynames
;
1217 while (fac_record
->c_name
!= NULL
) {
1218 if (!strcmp(fac_record
->c_name
, strValue
)) {
1219 logFacility
= fac_record
->c_val
;
1226 if(fac_record
->c_name
== NULL
)
1227 errx(1, "Unknown log facility name: %s", strValue
);
1232 SetupPunchFW(strValue
);
1236 logIpfwDenied
= yesNoValue
;;
1242 ReadConfigFile(const char *fileName
)
1250 file
= fopen(fileName
, "r");
1252 err(1, "cannot open config file %s", fileName
);
1254 while ((buf
= fgetln(file
, &len
)) != NULL
) {
1255 if (buf
[len
- 1] == '\n')
1256 buf
[len
- 1] = '\0';
1258 errx(1, "config file format error: "
1259 "last line should end with newline");
1262 * Check for comments, strip off trailing spaces.
1264 if ((ptr
= strchr(buf
, '#')))
1266 for (ptr
= buf
; isspace(*ptr
); ++ptr
)
1270 for (p
= strchr(buf
, '\0'); isspace(*--p
);)
1275 * Extract option name.
1278 while (*ptr
&& !isspace(*ptr
))
1286 * Skip white space between name and parms.
1288 while (*ptr
&& isspace(*ptr
))
1291 ParseOption(option
, *ptr
? ptr
: NULL
);
1302 struct OptionInfo
* info
;
1304 fprintf(stderr
, "Recognized options:\n\n");
1306 max
= sizeof(optionTable
) / sizeof(struct OptionInfo
);
1307 for (i
= 0, info
= optionTable
; i
< max
; i
++, info
++) {
1308 fprintf(stderr
, "-%-20s %s\n", info
->name
,
1309 info
->parmDescription
);
1311 if (info
->shortName
)
1312 fprintf(stderr
, "-%-20s %s\n", info
->shortName
,
1313 info
->parmDescription
);
1315 fprintf(stderr
, " %s\n\n", info
->description
);
1322 SetupPortRedirect(const char *parms
)
1327 struct in_addr localAddr
;
1328 struct in_addr publicAddr
;
1329 struct in_addr remoteAddr
;
1330 port_range portRange
;
1331 u_short localPort
= 0;
1332 u_short publicPort
= 0;
1333 u_short remotePort
= 0;
1334 u_short numLocalPorts
= 0;
1335 u_short numPublicPorts
= 0;
1336 u_short numRemotePorts
= 0;
1341 struct alias_link
*alink
= NULL
;
1347 protoName
= strtok(buf
, " \t");
1349 errx(1, "redirect_port: missing protocol");
1351 proto
= StrToProto(protoName
);
1353 * Extract local address.
1355 ptr
= strtok(NULL
, " \t");
1357 errx(1, "redirect_port: missing local address");
1359 separator
= strchr(ptr
, ',');
1360 if (separator
) { /* LSNAT redirection syntax. */
1361 localAddr
.s_addr
= INADDR_NONE
;
1366 if (StrToAddrAndPortRange(ptr
, &localAddr
, protoName
, &portRange
) != 0 )
1367 errx(1, "redirect_port: invalid local port range");
1369 localPort
= GETLOPORT(portRange
);
1370 numLocalPorts
= GETNUMPORTS(portRange
);
1375 * Extract public port and optionally address.
1377 ptr
= strtok(NULL
, " \t");
1379 errx(1, "redirect_port: missing public port");
1381 separator
= strchr(ptr
, ':');
1383 if (StrToAddrAndPortRange(ptr
, &publicAddr
, protoName
, &portRange
) != 0 )
1384 errx(1, "redirect_port: invalid public port range");
1386 publicAddr
.s_addr
= INADDR_ANY
;
1387 if (StrToPortRange(ptr
, protoName
, &portRange
) != 0)
1388 errx(1, "redirect_port: invalid public port range");
1391 publicPort
= GETLOPORT(portRange
);
1392 numPublicPorts
= GETNUMPORTS(portRange
);
1395 * Extract remote address and optionally port.
1397 ptr
= strtok(NULL
, " \t");
1399 separator
= strchr(ptr
, ':');
1401 if (StrToAddrAndPortRange(ptr
, &remoteAddr
, protoName
, &portRange
) != 0)
1402 errx(1, "redirect_port: invalid remote port range");
1404 SETLOPORT(portRange
, 0);
1405 SETNUMPORTS(portRange
, 1);
1406 StrToAddr(ptr
, &remoteAddr
);
1409 SETLOPORT(portRange
, 0);
1410 SETNUMPORTS(portRange
, 1);
1411 remoteAddr
.s_addr
= INADDR_ANY
;
1414 remotePort
= GETLOPORT(portRange
);
1415 numRemotePorts
= GETNUMPORTS(portRange
);
1418 * Make sure port ranges match up, then add the redirect ports.
1420 if (numLocalPorts
!= numPublicPorts
)
1421 errx(1, "redirect_port: port ranges must be equal in size");
1423 /* Remote port range is allowed to be '0' which means all ports. */
1424 if (numRemotePorts
!= numLocalPorts
&& (numRemotePorts
!= 1 || remotePort
!= 0))
1425 errx(1, "redirect_port: remote port must be 0 or equal to local port range in size");
1427 for (i
= 0 ; i
< numPublicPorts
; ++i
) {
1428 /* If remotePort is all ports, set it to 0. */
1429 u_short remotePortCopy
= remotePort
+ i
;
1430 if (numRemotePorts
== 1 && remotePort
== 0)
1433 alink
= PacketAliasRedirectPort(localAddr
,
1434 htons(localPort
+ i
),
1436 htons(remotePortCopy
),
1438 htons(publicPort
+ i
),
1443 * Setup LSNAT server pool.
1445 if (serverPool
!= NULL
&& alink
!= NULL
) {
1446 ptr
= strtok(serverPool
, ",");
1447 while (ptr
!= NULL
) {
1448 if (StrToAddrAndPortRange(ptr
, &localAddr
, protoName
, &portRange
) != 0)
1449 errx(1, "redirect_port: invalid local port range");
1451 localPort
= GETLOPORT(portRange
);
1452 if (GETNUMPORTS(portRange
) != 1)
1453 errx(1, "redirect_port: local port must be single in this context");
1454 PacketAliasAddServer(alink
, localAddr
, htons(localPort
));
1455 ptr
= strtok(NULL
, ",");
1461 SetupProtoRedirect(const char *parms
)
1465 struct in_addr localAddr
;
1466 struct in_addr publicAddr
;
1467 struct in_addr remoteAddr
;
1470 struct protoent
*protoent
;
1476 protoName
= strtok(buf
, " \t");
1478 errx(1, "redirect_proto: missing protocol");
1480 protoent
= getprotobyname(protoName
);
1481 if (protoent
== NULL
)
1482 errx(1, "redirect_proto: unknown protocol %s", protoName
);
1484 proto
= protoent
->p_proto
;
1486 * Extract local address.
1488 ptr
= strtok(NULL
, " \t");
1490 errx(1, "redirect_proto: missing local address");
1492 StrToAddr(ptr
, &localAddr
);
1494 * Extract optional public address.
1496 ptr
= strtok(NULL
, " \t");
1498 StrToAddr(ptr
, &publicAddr
);
1500 publicAddr
.s_addr
= INADDR_ANY
;
1502 * Extract optional remote address.
1504 ptr
= strtok(NULL
, " \t");
1506 StrToAddr(ptr
, &remoteAddr
);
1508 remoteAddr
.s_addr
= INADDR_ANY
;
1510 * Create aliasing link.
1512 PacketAliasRedirectProto(localAddr
, remoteAddr
, publicAddr
, proto
);
1516 SetupAddressRedirect(const char *parms
)
1521 struct in_addr localAddr
;
1522 struct in_addr publicAddr
;
1524 struct alias_link
*alink
;
1528 * Extract local address.
1530 ptr
= strtok(buf
, " \t");
1532 errx(1, "redirect_address: missing local address");
1534 separator
= strchr(ptr
, ',');
1535 if (separator
) { /* LSNAT redirection syntax. */
1536 localAddr
.s_addr
= INADDR_NONE
;
1539 StrToAddr(ptr
, &localAddr
);
1543 * Extract public address.
1545 ptr
= strtok(NULL
, " \t");
1547 errx(1, "redirect_address: missing public address");
1549 StrToAddr(ptr
, &publicAddr
);
1550 alink
= PacketAliasRedirectAddr(localAddr
, publicAddr
);
1553 * Setup LSNAT server pool.
1555 if (serverPool
!= NULL
&& alink
!= NULL
) {
1556 ptr
= strtok(serverPool
, ",");
1557 while (ptr
!= NULL
) {
1558 StrToAddr(ptr
, &localAddr
);
1559 PacketAliasAddServer(alink
, localAddr
, htons(~0));
1560 ptr
= strtok(NULL
, ",");
1566 StrToAddr(const char *str
, struct in_addr
*addr
)
1570 if (inet_aton(str
, addr
))
1573 hp
= gethostbyname(str
);
1575 errx(1, "unknown host %s", str
);
1577 memcpy(addr
, hp
->h_addr
, sizeof(struct in_addr
));
1581 StrToPort(const char *str
, const char *proto
)
1587 port
= strtol(str
, &end
, 10);
1591 sp
= getservbyname(str
, proto
);
1593 errx(1, "unknown service %s/%s", str
, proto
);
1599 StrToPortRange(const char *str
, const char *proto
, port_range
*portRange
)
1607 /* First see if this is a service, return corresponding port if so. */
1608 sp
= getservbyname(str
,proto
);
1610 SETLOPORT(*portRange
, ntohs(sp
->s_port
));
1611 SETNUMPORTS(*portRange
, 1);
1615 /* Not a service, see if it's a single port or port range. */
1616 sep
= strchr(str
, '-');
1618 SETLOPORT(*portRange
, strtol(str
, &end
, 10));
1621 SETNUMPORTS(*portRange
, 1);
1625 /* Error in port range field. */
1626 errx(1, "unknown service %s/%s", str
, proto
);
1629 /* Port range, get the values and sanity check. */
1630 sscanf(str
, "%hu-%hu", &loPort
, &hiPort
);
1631 SETLOPORT(*portRange
, loPort
);
1632 SETNUMPORTS(*portRange
, 0); /* Error by default */
1633 if (loPort
<= hiPort
)
1634 SETNUMPORTS(*portRange
, hiPort
- loPort
+ 1);
1636 if (GETNUMPORTS(*portRange
) == 0)
1637 errx(1, "invalid port range %s", str
);
1644 StrToProto(const char *str
)
1646 if (!strcmp(str
, "tcp"))
1649 if (!strcmp(str
, "udp"))
1652 errx(1, "unknown protocol %s. Expected tcp or udp", str
);
1656 StrToAddrAndPortRange(const char *str
, struct in_addr
*addr
, char *proto
, port_range
*portRange
)
1660 ptr
= strchr(str
, ':');
1662 errx(1, "%s is missing port number", str
);
1667 StrToAddr(str
, addr
);
1668 return StrToPortRange(ptr
, proto
, portRange
);
1672 SetupPunchFW(const char *strValue
)
1674 unsigned int base
, num
;
1676 if (sscanf(strValue
, "%u:%u", &base
, &num
) != 2)
1677 errx(1, "punch_fw: basenumber:count parameter required");
1679 PacketAliasSetFWBase(base
, num
);
1680 PacketAliasSetMode(PKT_ALIAS_PUNCH_FW
, PKT_ALIAS_PUNCH_FW
);