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);
746 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
747 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
749 for (i
= 1; i
< RTA_IFA
; i
<<= 1)
750 if (ifam
->ifam_addrs
& i
)
751 ADVANCE(cp
, (struct sockaddr
*)cp
);
752 if (((struct sockaddr
*)cp
)->sa_family
== AF_INET
) {
753 s_in
= (struct sockaddr_in
*)cp
;
759 errx(1, "%s: cannot get interface address", ifn
);
761 PacketAliasSetAddress(s_in
->sin_addr
);
762 syslog(LOG_INFO
, "Aliasing to %s, mtu %d bytes",
763 inet_ntoa(s_in
->sin_addr
), ifMTU
);
769 Quit(const char *msg
)
776 Warn(const char *msg
)
779 syslog(LOG_ALERT
, "%s (%m)", msg
);
785 RefreshAddr(int sig __unused
)
792 InitiateShutdown(int sig __unused
)
796 * Start timer to allow kernel gracefully
797 * shutdown existing connections when system
800 sa
.sa_handler
= Shutdown
;
802 sigemptyset(&sa
.sa_mask
);
803 sigaction(SIGALRM
, &sa
, NULL
);
804 ualarm(exitDelay
*1000, 1000);
808 Shutdown(int sig __unused
)
814 * Different options recognized by this program.
849 * Option information structure (used by ParseOption).
856 const char* parmDescription
;
857 const char* description
;
859 const char* shortName
;
863 * Table of known options.
866 static struct OptionInfo optionTable
[] = {
868 PKT_ALIAS_UNREGISTERED_ONLY
,
871 "alias only unregistered addresses",
884 PKT_ALIAS_PROXY_ONLY
,
895 "operate in reverse mode",
900 PKT_ALIAS_DENY_INCOMING
,
903 "allow incoming connections",
908 PKT_ALIAS_USE_SOCKETS
,
911 "use sockets to inhibit port conflict",
916 PKT_ALIAS_SAME_PORTS
,
919 "try to keep original port numbers for connections",
927 "verbose mode, dump packet information",
935 "dynamic mode, automatically detect interface address changes",
942 "number|service_name",
943 "set port for incoming packets",
950 "number|service_name",
951 "set port for outgoing packets",
958 "number|service_name",
959 "set port (defaults to natd/divert)",
967 "address to use for aliasing",
975 "address to use for incoming sessions",
983 "take aliasing address from interface",
990 "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
992 "add transparent proxying / destination NAT",
999 "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
1000 " [remote_addr[:remote_port_range]]",
1001 "redirect a port (or ports) for incoming traffic",
1008 "proto local_addr [public_addr] [remote_addr]",
1009 "redirect packets of a given proto",
1016 "local_addr[,...] public_addr",
1017 "define mapping between local and public addresses",
1025 "read options from configuration file",
1033 "enable logging of denied incoming packets",
1041 "name of syslog facility to use for logging",
1049 "punch holes in the firewall for incoming FTP/IRC DCC connections",
1057 "log packets converted by natd, but denied by ipfw",
1064 "delay in ms before daemon exit after signal",
1070 ParseOption(const char *option
, const char *parms
)
1073 struct OptionInfo
* info
;
1078 const char* strValue
;
1079 struct in_addr addrValue
;
1082 CODE
* fac_record
= NULL
;
1084 * Find option from table.
1086 max
= sizeof(optionTable
) / sizeof(struct OptionInfo
);
1087 for (i
= 0, info
= optionTable
; i
< max
; i
++, info
++) {
1088 if (!strcmp(info
->name
, option
))
1091 if (info
->shortName
)
1092 if (!strcmp(info
->shortName
, option
))
1097 warnx("unknown option %s", option
);
1108 switch (info
->parm
) {
1113 if (!strcmp(parms
, "yes"))
1116 if (!strcmp(parms
, "no"))
1119 errx(1, "%s needs yes/no parameter", option
);
1124 errx(1, "%s needs service name or "
1125 "port number parameter",
1128 uNumValue
= StrToPort(parms
, "divert");
1133 numValue
= strtol(parms
, &end
, 10);
1138 errx(1, "%s needs numeric parameter", option
);
1144 errx(1, "%s needs parameter", option
);
1149 errx(1, "%s does not take parameters", option
);
1154 errx(1, "%s needs address/host parameter", option
);
1156 StrToAddr(parms
, &addrValue
);
1160 switch (info
->type
) {
1161 case PacketAliasOption
:
1163 aliasValue
= yesNoValue
? info
->packetAliasOpt
: 0;
1164 PacketAliasSetMode(aliasValue
, info
->packetAliasOpt
);
1168 verbose
= yesNoValue
;
1172 dynamicMode
= yesNoValue
;
1180 outPort
= uNumValue
;
1184 inOutPort
= uNumValue
;
1188 memcpy(&aliasAddr
, &addrValue
, sizeof(struct in_addr
));
1192 PacketAliasSetTarget(addrValue
);
1196 SetupPortRedirect(strValue
);
1200 SetupProtoRedirect(strValue
);
1203 case RedirectAddress
:
1204 SetupAddressRedirect(strValue
);
1208 PacketAliasProxyRule(strValue
);
1215 ifName
= strdup(strValue
);
1219 ReadConfigFile(strValue
);
1223 logDropped
= yesNoValue
;
1228 fac_record
= facilitynames
;
1229 while (fac_record
->c_name
!= NULL
) {
1230 if (!strcmp(fac_record
->c_name
, strValue
)) {
1231 logFacility
= fac_record
->c_val
;
1238 if(fac_record
->c_name
== NULL
)
1239 errx(1, "Unknown log facility name: %s", strValue
);
1244 SetupPunchFW(strValue
);
1248 logIpfwDenied
= yesNoValue
;
1251 if (numValue
< 0 || numValue
> MAX_EXIT_DELAY
)
1252 errx(1, "Incorrect exit delay: %d", numValue
);
1253 exitDelay
= numValue
;
1259 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
))
1303 * Skip white space between name and parms.
1305 while (*ptr
&& isspace(*ptr
))
1308 ParseOption(option
, *ptr
? ptr
: NULL
);
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
++) {
1325 fprintf(stderr
, "-%-20s %s\n", info
->name
,
1326 info
->parmDescription
);
1328 if (info
->shortName
)
1329 fprintf(stderr
, "-%-20s %s\n", info
->shortName
,
1330 info
->parmDescription
);
1332 fprintf(stderr
, " %s\n\n", info
->description
);
1339 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
;
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");
1403 publicAddr
.s_addr
= INADDR_ANY
;
1404 if (StrToPortRange(ptr
, protoName
, &portRange
) != 0)
1405 errx(1, "redirect_port: invalid public port range");
1408 publicPort
= GETLOPORT(portRange
);
1409 numPublicPorts
= GETNUMPORTS(portRange
);
1412 * Extract remote address and optionally port.
1414 ptr
= strtok(NULL
, " \t");
1416 separator
= strchr(ptr
, ':');
1418 if (StrToAddrAndPortRange(ptr
, &remoteAddr
, protoName
, &portRange
) != 0)
1419 errx(1, "redirect_port: invalid remote port range");
1421 SETLOPORT(portRange
, 0);
1422 SETNUMPORTS(portRange
, 1);
1423 StrToAddr(ptr
, &remoteAddr
);
1426 SETLOPORT(portRange
, 0);
1427 SETNUMPORTS(portRange
, 1);
1428 remoteAddr
.s_addr
= INADDR_ANY
;
1431 remotePort
= GETLOPORT(portRange
);
1432 numRemotePorts
= GETNUMPORTS(portRange
);
1435 * Make sure port ranges match up, then add the redirect ports.
1437 if (numLocalPorts
!= numPublicPorts
)
1438 errx(1, "redirect_port: port ranges must be equal in size");
1440 /* Remote port range is allowed to be '0' which means all ports. */
1441 if (numRemotePorts
!= numLocalPorts
&& (numRemotePorts
!= 1 || remotePort
!= 0))
1442 errx(1, "redirect_port: remote port must be 0 or equal to local port range in size");
1444 for (i
= 0 ; i
< numPublicPorts
; ++i
) {
1445 /* If remotePort is all ports, set it to 0. */
1446 u_short remotePortCopy
= remotePort
+ i
;
1447 if (numRemotePorts
== 1 && remotePort
== 0)
1450 alink
= PacketAliasRedirectPort(localAddr
,
1451 htons(localPort
+ i
),
1453 htons(remotePortCopy
),
1455 htons(publicPort
+ i
),
1460 * Setup LSNAT server pool.
1462 if (serverPool
!= NULL
&& alink
!= NULL
) {
1463 ptr
= strtok(serverPool
, ",");
1464 while (ptr
!= NULL
) {
1465 if (StrToAddrAndPortRange(ptr
, &localAddr
, protoName
, &portRange
) != 0)
1466 errx(1, "redirect_port: invalid local port range");
1468 localPort
= GETLOPORT(portRange
);
1469 if (GETNUMPORTS(portRange
) != 1)
1470 errx(1, "redirect_port: local port must be single in this context");
1471 PacketAliasAddServer(alink
, localAddr
, htons(localPort
));
1472 ptr
= strtok(NULL
, ",");
1478 SetupProtoRedirect(const char *parms
)
1482 struct in_addr localAddr
;
1483 struct in_addr publicAddr
;
1484 struct in_addr remoteAddr
;
1487 struct protoent
*protoent
;
1493 protoName
= strtok(buf
, " \t");
1495 errx(1, "redirect_proto: missing protocol");
1497 protoent
= getprotobyname(protoName
);
1498 if (protoent
== NULL
)
1499 errx(1, "redirect_proto: unknown protocol %s", protoName
);
1501 proto
= protoent
->p_proto
;
1503 * Extract local address.
1505 ptr
= strtok(NULL
, " \t");
1507 errx(1, "redirect_proto: missing local address");
1509 StrToAddr(ptr
, &localAddr
);
1511 * Extract optional public address.
1513 ptr
= strtok(NULL
, " \t");
1515 StrToAddr(ptr
, &publicAddr
);
1517 publicAddr
.s_addr
= INADDR_ANY
;
1519 * Extract optional remote address.
1521 ptr
= strtok(NULL
, " \t");
1523 StrToAddr(ptr
, &remoteAddr
);
1525 remoteAddr
.s_addr
= INADDR_ANY
;
1527 * Create aliasing link.
1529 PacketAliasRedirectProto(localAddr
, remoteAddr
, publicAddr
, proto
);
1533 SetupAddressRedirect(const char *parms
)
1538 struct in_addr localAddr
;
1539 struct in_addr publicAddr
;
1541 struct alias_link
*alink
;
1545 * Extract local address.
1547 ptr
= strtok(buf
, " \t");
1549 errx(1, "redirect_address: missing local address");
1551 separator
= strchr(ptr
, ',');
1552 if (separator
) { /* LSNAT redirection syntax. */
1553 localAddr
.s_addr
= INADDR_NONE
;
1556 StrToAddr(ptr
, &localAddr
);
1560 * Extract public address.
1562 ptr
= strtok(NULL
, " \t");
1564 errx(1, "redirect_address: missing public address");
1566 StrToAddr(ptr
, &publicAddr
);
1567 alink
= PacketAliasRedirectAddr(localAddr
, publicAddr
);
1570 * Setup LSNAT server pool.
1572 if (serverPool
!= NULL
&& alink
!= NULL
) {
1573 ptr
= strtok(serverPool
, ",");
1574 while (ptr
!= NULL
) {
1575 StrToAddr(ptr
, &localAddr
);
1576 PacketAliasAddServer(alink
, localAddr
, htons(~0));
1577 ptr
= strtok(NULL
, ",");
1583 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
));
1598 StrToPort(const char *str
, const char *proto
)
1604 port
= strtol(str
, &end
, 10);
1608 sp
= getservbyname(str
, proto
);
1610 errx(1, "unknown service %s/%s", str
, proto
);
1616 StrToPortRange(const char *str
, const char *proto
, port_range
*portRange
)
1624 /* First see if this is a service, return corresponding port if so. */
1625 sp
= getservbyname(str
,proto
);
1627 SETLOPORT(*portRange
, ntohs(sp
->s_port
));
1628 SETNUMPORTS(*portRange
, 1);
1632 /* Not a service, see if it's a single port or port range. */
1633 sep
= strchr(str
, '-');
1635 SETLOPORT(*portRange
, strtol(str
, &end
, 10));
1638 SETNUMPORTS(*portRange
, 1);
1642 /* Error in port range field. */
1643 errx(1, "unknown service %s/%s", str
, proto
);
1646 /* Port range, get the values and sanity check. */
1647 sscanf(str
, "%hu-%hu", &loPort
, &hiPort
);
1648 SETLOPORT(*portRange
, loPort
);
1649 SETNUMPORTS(*portRange
, 0); /* Error by default */
1650 if (loPort
<= hiPort
)
1651 SETNUMPORTS(*portRange
, hiPort
- loPort
+ 1);
1653 if (GETNUMPORTS(*portRange
) == 0)
1654 errx(1, "invalid port range %s", str
);
1661 StrToProto(const char *str
)
1663 if (!strcmp(str
, "tcp"))
1666 if (!strcmp(str
, "udp"))
1669 errx(1, "unknown protocol %s. Expected tcp or udp", str
);
1673 StrToAddrAndPortRange(const char *str
, struct in_addr
*addr
, char *proto
, port_range
*portRange
)
1677 ptr
= strchr(str
, ':');
1679 errx(1, "%s is missing port number", str
);
1684 StrToAddr(str
, addr
);
1685 return StrToPortRange(ptr
, proto
, portRange
);
1689 SetupPunchFW(const char *strValue
)
1691 unsigned int base
, num
;
1693 if (sscanf(strValue
, "%u:%u", &base
, &num
) != 2)
1694 errx(1, "punch_fw: basenumber:count parameter required");
1696 PacketAliasSetFWBase(base
, num
);
1697 PacketAliasSetMode(PKT_ALIAS_PUNCH_FW
, PKT_ALIAS_PUNCH_FW
);