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 $
17 #include <sys/param.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 <netinet/tcp.h>
26 #include <netinet/udp.h>
27 #include <netinet/ip_icmp.h>
29 #include <net/if_dl.h>
30 #include <net/route.h>
31 #include <arpa/inet.h>
48 * Default values for input and output
49 * divert socket ports.
52 #define DEFAULT_SERVICE "natd"
55 * Definition of a port range, and macros to deal with values.
56 * FORMAT: HI 16-bits == first port in range, 0 == all ports.
57 * LO 16-bits == number of ports in range
58 * NOTES: - Port values are not stored in network byte order.
61 typedef u_long port_range
;
63 #define GETLOPORT(x) ((x) >> 0x10)
64 #define GETNUMPORTS(x) ((x) & 0x0000ffff)
65 #define GETHIPORT(x) (GETLOPORT((x)) + GETNUMPORTS((x)))
67 /* Set y to be the low-port value in port_range variable x. */
68 #define SETLOPORT(x,y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
70 /* Set y to be the number of ports in port_range variable x. */
71 #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y))
74 * Function prototypes.
77 static void DoAliasing(int, int);
78 static void DaemonMode(void);
79 static void HandleRoutingInfo(int);
80 static void Usage(void);
81 static char* FormatPacket(struct ip
*);
82 static void PrintPacket(struct ip
*);
83 static void SyslogPacket(struct ip
*, int, const char *);
84 static void SetAliasAddressFromIfName(const char *);
85 static void InitiateShutdown(int);
86 static void Shutdown(int);
87 static void RefreshAddr(int);
88 static void ParseOption(const char *, const char *);
89 static void ReadConfigFile(const char *);
90 static void SetupPortRedirect(const char *);
91 static void SetupProtoRedirect(const char *);
92 static void SetupAddressRedirect(const char *);
93 static void StrToAddr(const char *, struct in_addr
*);
94 static u_short
StrToPort(const char *, const char *);
95 static int StrToPortRange(const char *, const char *, port_range
*);
96 static int StrToProto(const char *);
97 static int StrToAddrAndPortRange(const char *, struct in_addr
*, char *, port_range
*);
98 static void ParseArgs(int, char **);
99 static void SetupPunchFW(const char *);
106 static int background
;
107 static volatile sig_atomic_t running
;
108 static volatile sig_atomic_t assignAliasAddr
;
111 static u_short inPort
;
112 static u_short outPort
;
113 static u_short inOutPort
;
114 static struct in_addr aliasAddr
;
115 static int dynamicMode
;
117 static int aliasOverhead
;
119 static int dropIgnoredIncoming
;
120 static int logDropped
;
121 static int logFacility
;
122 static int logIpfwDenied
;
123 static int exitDelay
;
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
;
160 exitDelay
= EXIT_DELAY
;
162 ParseArgs(argc
, argv
);
164 * Log ipfw(8) denied packets by default in verbose mode.
166 if (logIpfwDenied
== -1)
167 logIpfwDenied
= verbose
;
169 * Open syslog channel.
171 openlog("natd", LOG_CONS
| LOG_PID
| (verbose
? LOG_PERROR
: 0),
174 * Check that valid aliasing address has been given.
176 if (aliasAddr
.s_addr
== INADDR_NONE
&& ifName
== NULL
)
177 errx(1, "aliasing address not given");
179 if (aliasAddr
.s_addr
!= INADDR_NONE
&& ifName
!= NULL
)
180 errx(1, "both alias address and interface "
181 "name are not allowed");
183 * Check that valid port number is known.
185 if (inPort
!= 0 || outPort
!= 0)
186 if (inPort
== 0 || outPort
== 0)
187 errx(1, "both input and output ports are required");
189 if (inPort
== 0 && outPort
== 0 && inOutPort
== 0)
190 ParseOption("port", DEFAULT_SERVICE
);
193 * Check if ignored packets should be dropped.
195 dropIgnoredIncoming
= PacketAliasSetMode(0, 0);
196 dropIgnoredIncoming
&= PKT_ALIAS_DENY_INCOMING
;
198 * Create divert sockets. Use only one socket if -p was specified
199 * on command line. Otherwise, create separate sockets for
200 * outgoing and incoming connnections.
203 divertInOut
= socket(PF_INET
, SOCK_RAW
, IPPROTO_DIVERT
);
204 if (divertInOut
== -1)
205 Quit("Unable to create divert socket.");
213 addr
.sin_family
= AF_INET
;
214 addr
.sin_addr
.s_addr
= INADDR_ANY
;
215 addr
.sin_port
= inOutPort
;
217 if (bind(divertInOut
,
218 (struct sockaddr
*)&addr
,
220 Quit("Unable to bind divert socket.");
222 divertIn
= socket(PF_INET
, SOCK_RAW
, IPPROTO_DIVERT
);
224 Quit("Unable to create incoming divert socket.");
226 divertOut
= socket(PF_INET
, SOCK_RAW
, IPPROTO_DIVERT
);
228 Quit("Unable to create outgoing divert socket.");
233 * Bind divert sockets.
236 addr
.sin_family
= AF_INET
;
237 addr
.sin_addr
.s_addr
= INADDR_ANY
;
238 addr
.sin_port
= inPort
;
241 (struct sockaddr
*)&addr
,
243 Quit("Unable to bind incoming divert socket.");
245 addr
.sin_family
= AF_INET
;
246 addr
.sin_addr
.s_addr
= INADDR_ANY
;
247 addr
.sin_port
= outPort
;
250 (struct sockaddr
*)&addr
,
252 Quit("Unable to bind outgoing divert socket.");
255 * Create routing socket if interface name specified and in dynamic mode.
260 routeSock
= socket(PF_ROUTE
, SOCK_RAW
, 0);
262 Quit("Unable to create routing info socket.");
266 SetAliasAddressFromIfName(ifName
);
269 * Create socket for sending ICMP messages.
271 icmpSock
= socket(AF_INET
, SOCK_RAW
, IPPROTO_ICMP
);
273 Quit("Unable to create ICMP socket.");
276 * And disable reads for the socket, otherwise it slowly fills
277 * up with received icmps which we do not use.
279 shutdown(icmpSock
, SHUT_RD
);
282 * Become a daemon unless verbose mode was requested.
287 * Catch signals to manage shutdown and
288 * refresh of interface address.
291 sigemptyset(&sa
.sa_mask
);
293 sa
.sa_handler
= InitiateShutdown
;
295 sa
.sa_handler
= Shutdown
;
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
)
323 if (divertInOut
!= -1 && !ifName
) {
325 * When using only one socket, just call
326 * DoAliasing repeatedly to process packets.
328 DoAliasing(divertInOut
, DONT_KNOW
);
332 * Build read mask from socket descriptors to select.
336 * Check if new packets are available.
339 FD_SET(divertIn
, &readMask
);
342 FD_SET(divertOut
, &readMask
);
344 if (divertInOut
!= -1)
345 FD_SET(divertInOut
, &readMask
);
347 * Routing info is processed always.
350 FD_SET(routeSock
, &readMask
);
352 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
);
394 pidFile
= fopen(PIDFILE
, "w");
396 fprintf(pidFile
, "%d\n", getpid());
402 ParseArgs(int argc
, char **argv
)
407 int len
; /* bounds checking */
409 for (arg
= 1; arg
< argc
; arg
++) {
412 warnx("invalid option %s", opt
);
419 while (arg
< argc
- 1) {
420 if (argv
[arg
+ 1][0] == '-')
424 strncat(parmBuf
, " ", sizeof(parmBuf
) - (len
+ 1));
425 len
+= strlen(parmBuf
+ len
);
429 strncat(parmBuf
, argv
[arg
], sizeof(parmBuf
) - (len
+ 1));
430 len
+= strlen(parmBuf
+ len
);
434 ParseOption(opt
+ 1, (len
? parmBuf
: NULL
));
440 DoAliasing(int fd
, int direction
)
444 char buf
[IP_MAXPACKET
];
445 struct sockaddr_in addr
;
452 if (assignAliasAddr
) {
453 SetAliasAddressFromIfName(ifName
);
457 * Get packet from socket.
459 addrSize
= sizeof addr
;
460 origBytes
= recvfrom(fd
,
464 (struct sockaddr
*)&addr
,
467 if (origBytes
== -1) {
469 Warn("read from divert socket failed");
474 * This is a IP packet.
476 ip
= (struct ip
*)buf
;
477 if (direction
== DONT_KNOW
) {
478 if (addr
.sin_addr
.s_addr
== INADDR_ANY
)
486 * Print packet direction and protocol type.
488 printf(direction
== OUTPUT
? "Out " : "In ");
504 printf("[%d] ", ip
->ip_p
);
513 if (direction
== OUTPUT
) {
515 * Outgoing packets. Do aliasing.
517 PacketAliasOut(buf
, IP_MAXPACKET
);
522 status
= PacketAliasIn(buf
, IP_MAXPACKET
);
523 if (status
== PKT_ALIAS_IGNORED
&&
524 dropIgnoredIncoming
) {
526 printf(" dropped.\n");
529 SyslogPacket(ip
, LOG_WARNING
, "denied");
535 * Length might have changed during aliasing.
537 bytes
= ntohs(ip
->ip_len
);
539 * Update alias overhead size for outgoing packets.
541 if (direction
== OUTPUT
&&
542 bytes
- origBytes
> aliasOverhead
)
543 aliasOverhead
= bytes
- origBytes
;
547 * Print addresses after aliasing.
549 printf(" aliased to\n");
556 * Put packet back for processing.
562 (struct sockaddr
*)&addr
,
565 if (wrote
!= bytes
) {
566 if (errno
== EMSGSIZE
) {
567 if (direction
== OUTPUT
&&
569 SendNeedFragIcmp(icmpSock
,
571 ifMTU
- aliasOverhead
);
572 } else if (errno
== EACCES
&& logIpfwDenied
) {
573 sprintf(msgBuf
, "failed to write packet back");
580 HandleRoutingInfo(int fd
)
583 struct if_msghdr ifMsg
;
585 * Get packet from socket.
587 bytes
= read(fd
, &ifMsg
, sizeof ifMsg
);
589 Warn("read from routing socket failed");
593 if (ifMsg
.ifm_version
!= RTM_VERSION
) {
594 Warn("unexpected packet read from routing socket");
599 printf("Routing message %#x received.\n", ifMsg
.ifm_type
);
601 if ((ifMsg
.ifm_type
== RTM_NEWADDR
|| ifMsg
.ifm_type
== RTM_IFINFO
) &&
602 ifMsg
.ifm_index
== ifIndex
) {
604 printf("Interface address/MTU has probably changed.\n");
610 PrintPacket(struct ip
*ip
)
612 printf("%s", FormatPacket(ip
));
616 SyslogPacket(struct ip
*ip
, int priority
, const char *label
)
618 syslog(priority
, "%s %s", label
, FormatPacket(ip
));
622 FormatPacket(struct ip
*ip
)
624 static char buf
[256];
625 struct tcphdr
* tcphdr
;
626 struct udphdr
* udphdr
;
627 struct icmp
* icmphdr
;
631 strcpy(src
, inet_ntoa(ip
->ip_src
));
632 strcpy(dst
, inet_ntoa(ip
->ip_dst
));
636 tcphdr
= (struct tcphdr
*)((char *)ip
+ (ip
->ip_hl
<< 2));
637 sprintf(buf
, "[TCP] %s:%d -> %s:%d",
639 ntohs(tcphdr
->th_sport
),
641 ntohs(tcphdr
->th_dport
));
645 udphdr
= (struct udphdr
*)((char *)ip
+ (ip
->ip_hl
<< 2));
646 sprintf(buf
, "[UDP] %s:%d -> %s:%d",
648 ntohs(udphdr
->uh_sport
),
650 ntohs(udphdr
->uh_dport
));
654 icmphdr
= (struct icmp
*)((char *)ip
+ (ip
->ip_hl
<< 2));
655 sprintf(buf
, "[ICMP] %s -> %s %u(%u)",
663 sprintf(buf
, "[%d] %s -> %s ", ip
->ip_p
, src
, dst
);
671 SetAliasAddressFromIfName(const char *ifn
)
675 char *buf
, *lim
, *next
;
676 struct if_msghdr
*ifm
;
677 struct ifa_msghdr
*ifam
;
678 struct sockaddr_dl
*s_dl
;
679 struct sockaddr_in
*s_in
;
684 mib
[3] = AF_INET
; /* Only IP addresses please */
685 mib
[4] = NET_RT_IFLIST
;
686 mib
[5] = 0; /* ifIndex??? */
688 * Get interface data.
690 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) == -1)
691 err(1, "iflist-sysctl-estimate");
692 if ((buf
= malloc(needed
)) == NULL
)
693 errx(1, "malloc failed");
694 if (sysctl(mib
, 6, buf
, &needed
, NULL
, 0) == -1)
695 err(1, "iflist-sysctl-get");
698 * Loop through interfaces until one with
699 * given name is found. This is done to
700 * find correct interface index for routing
701 * message processing.
706 ifm
= (struct if_msghdr
*)next
;
707 next
+= ifm
->ifm_msglen
;
708 if (ifm
->ifm_version
!= RTM_VERSION
) {
710 warnx("routing message version %d "
711 "not understood", ifm
->ifm_version
);
714 if (ifm
->ifm_type
== RTM_IFINFO
) {
715 s_dl
= (struct sockaddr_dl
*)(ifm
+ 1);
716 if (strlen(ifn
) == s_dl
->sdl_nlen
&&
717 strncmp(ifn
, s_dl
->sdl_data
, s_dl
->sdl_nlen
) == 0) {
718 ifIndex
= ifm
->ifm_index
;
719 ifMTU
= ifm
->ifm_data
.ifi_mtu
;
725 errx(1, "unknown interface name %s", ifn
);
727 * Get interface address.
731 ifam
= (struct ifa_msghdr
*)next
;
732 next
+= ifam
->ifam_msglen
;
733 if (ifam
->ifam_version
!= RTM_VERSION
) {
735 warnx("routing message version %d "
736 "not understood", ifam
->ifam_version
);
739 if (ifam
->ifam_type
!= RTM_NEWADDR
)
741 if (ifam
->ifam_addrs
& RTA_IFA
) {
743 char *cp
= (char *)(ifam
+ 1);
745 for (i
= 1; i
< RTA_IFA
; i
<<= 1)
746 if (ifam
->ifam_addrs
& i
)
747 RT_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
);
800 ualarm(exitDelay
*1000, 1000);
804 Shutdown(int sig __unused
)
810 * Different options recognized by this program.
845 * Option information structure (used by ParseOption).
852 const char* parmDescription
;
853 const char* description
;
855 const char* shortName
;
859 * Table of known options.
862 static struct OptionInfo optionTable
[] = {
864 PKT_ALIAS_UNREGISTERED_ONLY
,
867 "alias only unregistered addresses",
880 PKT_ALIAS_PROXY_ONLY
,
891 "operate in reverse mode",
896 PKT_ALIAS_DENY_INCOMING
,
899 "allow incoming connections",
904 PKT_ALIAS_USE_SOCKETS
,
907 "use sockets to inhibit port conflict",
912 PKT_ALIAS_SAME_PORTS
,
915 "try to keep original port numbers for connections",
923 "verbose mode, dump packet information",
931 "dynamic mode, automatically detect interface address changes",
938 "number|service_name",
939 "set port for incoming packets",
946 "number|service_name",
947 "set port for outgoing packets",
954 "number|service_name",
955 "set port (defaults to natd/divert)",
963 "address to use for aliasing",
971 "address to use for incoming sessions",
979 "take aliasing address from interface",
986 "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
988 "add transparent proxying / destination NAT",
995 "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
996 " [remote_addr[:remote_port_range]]",
997 "redirect a port (or ports) for incoming traffic",
1004 "proto local_addr [public_addr] [remote_addr]",
1005 "redirect packets of a given proto",
1012 "local_addr[,...] public_addr",
1013 "define mapping between local and public addresses",
1021 "read options from configuration file",
1029 "enable logging of denied incoming packets",
1037 "name of syslog facility to use for logging",
1045 "punch holes in the firewall for incoming FTP/IRC DCC connections",
1053 "log packets converted by natd, but denied by ipfw",
1060 "delay in ms before daemon exit after signal",
1066 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
= NELEM(optionTable
);
1083 for (i
= 0, info
= optionTable
; i
< max
; i
++, info
++) {
1084 if (!strcmp(info
->name
, option
))
1087 if (info
->shortName
)
1088 if (!strcmp(info
->shortName
, option
))
1093 warnx("unknown option %s", option
);
1104 switch (info
->parm
) {
1109 if (!strcmp(parms
, "yes"))
1112 if (!strcmp(parms
, "no"))
1115 errx(1, "%s needs yes/no parameter", option
);
1120 errx(1, "%s needs service name or "
1121 "port number parameter",
1124 uNumValue
= StrToPort(parms
, "divert");
1129 numValue
= strtol(parms
, &end
, 10);
1134 errx(1, "%s needs numeric parameter", option
);
1140 errx(1, "%s needs parameter", option
);
1145 errx(1, "%s does not take parameters", option
);
1150 errx(1, "%s needs address/host parameter", option
);
1152 StrToAddr(parms
, &addrValue
);
1156 switch (info
->type
) {
1157 case PacketAliasOption
:
1159 aliasValue
= yesNoValue
? info
->packetAliasOpt
: 0;
1160 PacketAliasSetMode(aliasValue
, info
->packetAliasOpt
);
1164 verbose
= yesNoValue
;
1168 dynamicMode
= yesNoValue
;
1176 outPort
= uNumValue
;
1180 inOutPort
= uNumValue
;
1184 memcpy(&aliasAddr
, &addrValue
, sizeof(struct in_addr
));
1188 PacketAliasSetTarget(addrValue
);
1192 SetupPortRedirect(strValue
);
1196 SetupProtoRedirect(strValue
);
1199 case RedirectAddress
:
1200 SetupAddressRedirect(strValue
);
1204 PacketAliasProxyRule(strValue
);
1211 ifName
= strdup(strValue
);
1215 ReadConfigFile(strValue
);
1219 logDropped
= yesNoValue
;
1224 fac_record
= facilitynames
;
1225 while (fac_record
->c_name
!= NULL
) {
1226 if (!strcmp(fac_record
->c_name
, strValue
)) {
1227 logFacility
= fac_record
->c_val
;
1234 if(fac_record
->c_name
== NULL
)
1235 errx(1, "Unknown log facility name: %s", strValue
);
1240 SetupPunchFW(strValue
);
1244 logIpfwDenied
= yesNoValue
;
1247 if (numValue
< 0 || numValue
> MAX_EXIT_DELAY
)
1248 errx(1, "Incorrect exit delay: %d", numValue
);
1249 exitDelay
= numValue
;
1255 ReadConfigFile(const char *fileName
)
1263 file
= fopen(fileName
, "r");
1265 err(1, "cannot open config file %s", fileName
);
1267 while ((buf
= fgetln(file
, &len
)) != NULL
) {
1268 if (buf
[len
- 1] == '\n')
1269 buf
[len
- 1] = '\0';
1271 errx(1, "config file format error: "
1272 "last line should end with newline");
1275 * Check for comments, strip off trailing spaces.
1277 if ((ptr
= strchr(buf
, '#')))
1279 for (ptr
= buf
; isspace(*ptr
); ++ptr
)
1283 for (p
= strchr(buf
, '\0'); isspace(*--p
);)
1288 * Extract option name.
1291 while (*ptr
&& !isspace(*ptr
))
1299 * Skip white space between name and parms.
1301 while (*ptr
&& isspace(*ptr
))
1304 ParseOption(option
, *ptr
? ptr
: NULL
);
1315 struct OptionInfo
* info
;
1317 fprintf(stderr
, "Recognized options:\n\n");
1319 max
= NELEM(optionTable
);
1320 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
);
1335 SetupPortRedirect(const char *parms
)
1340 struct in_addr localAddr
;
1341 struct in_addr publicAddr
;
1342 struct in_addr remoteAddr
;
1343 port_range portRange
;
1344 u_short localPort
= 0;
1345 u_short publicPort
= 0;
1346 u_short remotePort
= 0;
1347 u_short numLocalPorts
= 0;
1348 u_short numPublicPorts
= 0;
1349 u_short numRemotePorts
= 0;
1354 struct alias_link
*alink
= NULL
;
1360 protoName
= strtok(buf
, " \t");
1362 errx(1, "redirect_port: missing protocol");
1364 proto
= StrToProto(protoName
);
1366 * Extract local address.
1368 ptr
= strtok(NULL
, " \t");
1370 errx(1, "redirect_port: missing local address");
1372 separator
= strchr(ptr
, ',');
1373 if (separator
) { /* LSNAT redirection syntax. */
1374 localAddr
.s_addr
= INADDR_NONE
;
1379 if (StrToAddrAndPortRange(ptr
, &localAddr
, protoName
, &portRange
) != 0 )
1380 errx(1, "redirect_port: invalid local port range");
1382 localPort
= GETLOPORT(portRange
);
1383 numLocalPorts
= GETNUMPORTS(portRange
);
1388 * Extract public port and optionally address.
1390 ptr
= strtok(NULL
, " \t");
1392 errx(1, "redirect_port: missing public port");
1394 separator
= strchr(ptr
, ':');
1396 if (StrToAddrAndPortRange(ptr
, &publicAddr
, protoName
, &portRange
) != 0 )
1397 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
);
1422 SETLOPORT(portRange
, 0);
1423 SETNUMPORTS(portRange
, 1);
1424 remoteAddr
.s_addr
= INADDR_ANY
;
1427 remotePort
= GETLOPORT(portRange
);
1428 numRemotePorts
= GETNUMPORTS(portRange
);
1431 * Make sure port ranges match up, then add the redirect ports.
1433 if (numLocalPorts
!= numPublicPorts
)
1434 errx(1, "redirect_port: port ranges must be equal in size");
1436 /* Remote port range is allowed to be '0' which means all ports. */
1437 if (numRemotePorts
!= numLocalPorts
&& (numRemotePorts
!= 1 || remotePort
!= 0))
1438 errx(1, "redirect_port: remote port must be 0 or equal to local port range in size");
1440 for (i
= 0 ; i
< numPublicPorts
; ++i
) {
1441 /* If remotePort is all ports, set it to 0. */
1442 u_short remotePortCopy
= remotePort
+ i
;
1443 if (numRemotePorts
== 1 && remotePort
== 0)
1446 alink
= PacketAliasRedirectPort(localAddr
,
1447 htons(localPort
+ i
),
1449 htons(remotePortCopy
),
1451 htons(publicPort
+ i
),
1456 * Setup LSNAT server pool.
1458 if (serverPool
!= NULL
&& alink
!= NULL
) {
1459 ptr
= strtok(serverPool
, ",");
1460 while (ptr
!= NULL
) {
1461 if (StrToAddrAndPortRange(ptr
, &localAddr
, protoName
, &portRange
) != 0)
1462 errx(1, "redirect_port: invalid local port range");
1464 localPort
= GETLOPORT(portRange
);
1465 if (GETNUMPORTS(portRange
) != 1)
1466 errx(1, "redirect_port: local port must be single in this context");
1467 PacketAliasAddServer(alink
, localAddr
, htons(localPort
));
1468 ptr
= strtok(NULL
, ",");
1474 SetupProtoRedirect(const char *parms
)
1478 struct in_addr localAddr
;
1479 struct in_addr publicAddr
;
1480 struct in_addr remoteAddr
;
1483 struct protoent
*protoent
;
1489 protoName
= strtok(buf
, " \t");
1491 errx(1, "redirect_proto: missing protocol");
1493 protoent
= getprotobyname(protoName
);
1494 if (protoent
== NULL
)
1495 errx(1, "redirect_proto: unknown protocol %s", protoName
);
1497 proto
= protoent
->p_proto
;
1499 * Extract local address.
1501 ptr
= strtok(NULL
, " \t");
1503 errx(1, "redirect_proto: missing local address");
1505 StrToAddr(ptr
, &localAddr
);
1507 * Extract optional public address.
1509 ptr
= strtok(NULL
, " \t");
1511 StrToAddr(ptr
, &publicAddr
);
1513 publicAddr
.s_addr
= INADDR_ANY
;
1515 * Extract optional remote address.
1517 ptr
= strtok(NULL
, " \t");
1519 StrToAddr(ptr
, &remoteAddr
);
1521 remoteAddr
.s_addr
= INADDR_ANY
;
1523 * Create aliasing link.
1525 PacketAliasRedirectProto(localAddr
, remoteAddr
, publicAddr
, proto
);
1529 SetupAddressRedirect(const char *parms
)
1534 struct in_addr localAddr
;
1535 struct in_addr publicAddr
;
1537 struct alias_link
*alink
;
1541 * Extract local address.
1543 ptr
= strtok(buf
, " \t");
1545 errx(1, "redirect_address: missing local address");
1547 separator
= strchr(ptr
, ',');
1548 if (separator
) { /* LSNAT redirection syntax. */
1549 localAddr
.s_addr
= INADDR_NONE
;
1552 StrToAddr(ptr
, &localAddr
);
1556 * Extract public address.
1558 ptr
= strtok(NULL
, " \t");
1560 errx(1, "redirect_address: missing public address");
1562 StrToAddr(ptr
, &publicAddr
);
1563 alink
= PacketAliasRedirectAddr(localAddr
, publicAddr
);
1566 * Setup LSNAT server pool.
1568 if (serverPool
!= NULL
&& alink
!= NULL
) {
1569 ptr
= strtok(serverPool
, ",");
1570 while (ptr
!= NULL
) {
1571 StrToAddr(ptr
, &localAddr
);
1572 PacketAliasAddServer(alink
, localAddr
, htons(~0));
1573 ptr
= strtok(NULL
, ",");
1579 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
));
1594 StrToPort(const char *str
, const char *proto
)
1600 port
= strtol(str
, &end
, 10);
1604 sp
= getservbyname(str
, proto
);
1606 errx(1, "unknown service %s/%s", str
, proto
);
1612 StrToPortRange(const char *str
, const char *proto
, port_range
*portRange
)
1620 /* First see if this is a service, return corresponding port if so. */
1621 sp
= getservbyname(str
,proto
);
1623 SETLOPORT(*portRange
, ntohs(sp
->s_port
));
1624 SETNUMPORTS(*portRange
, 1);
1628 /* Not a service, see if it's a single port or port range. */
1629 sep
= strchr(str
, '-');
1631 SETLOPORT(*portRange
, strtol(str
, &end
, 10));
1634 SETNUMPORTS(*portRange
, 1);
1638 /* Error in port range field. */
1639 errx(1, "unknown service %s/%s", str
, proto
);
1642 /* Port range, get the values and sanity check. */
1643 sscanf(str
, "%hu-%hu", &loPort
, &hiPort
);
1644 SETLOPORT(*portRange
, loPort
);
1645 SETNUMPORTS(*portRange
, 0); /* Error by default */
1646 if (loPort
<= hiPort
)
1647 SETNUMPORTS(*portRange
, hiPort
- loPort
+ 1);
1649 if (GETNUMPORTS(*portRange
) == 0)
1650 errx(1, "invalid port range %s", str
);
1657 StrToProto(const char *str
)
1659 if (!strcmp(str
, "tcp"))
1662 if (!strcmp(str
, "udp"))
1665 errx(1, "unknown protocol %s. Expected tcp or udp", str
);
1669 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
);