2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 * natd - Network Address Translation Daemon for FreeBSD.
28 * This software is provided free of charge, with no
29 * warranty of any kind, either expressed or implied.
30 * Use at your own risk.
32 * You may copy, modify and distribute this software (natd.c) freely.
34 * Ari Suutari <suutari@iki.fi>
37 * $FreeBSD: src/sbin/natd/natd.c,v 1.25.2.3 2000/07/11 20:00:57 ru Exp $
42 #include <sys/types.h>
43 #include <sys/socket.h>
44 #include <sys/sysctl.h>
47 #include <netinet/in.h>
48 #include <netinet/in_systm.h>
49 #include <netinet/ip.h>
50 #include <netinet/tcp.h>
51 #include <netinet/udp.h>
52 #include <netinet/ip_icmp.h>
54 #include <net/if_dl.h>
55 #include <net/route.h>
56 #include <arpa/inet.h>
73 * Default values for input and output
74 * divert socket ports.
77 #define DEFAULT_SERVICE "natd"
80 * Definition of a port range, and macros to deal with values.
81 * FORMAT: HI 16-bits == first port in range, 0 == all ports.
82 * LO 16-bits == number of ports in range
83 * NOTES: - Port values are not stored in network byte order.
86 typedef u_long port_range
;
88 #define GETLOPORT(x) ((x) >> 0x10)
89 #define GETNUMPORTS(x) ((x) & 0x0000ffff)
90 #define GETHIPORT(x) (GETLOPORT((x)) + GETNUMPORTS((x)))
92 /* Set y to be the low-port value in port_range variable x. */
93 #define SETLOPORT(x,y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
95 /* Set y to be the number of ports in port_range variable x. */
96 #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y))
99 * Function prototypes.
102 static void DoAliasing (int fd
, int direction
);
103 static void DaemonMode (void);
104 static void HandleRoutingInfo (int fd
);
105 static void Usage (void);
106 static char* FormatPacket (struct ip
*);
107 static void PrintPacket (struct ip
*);
108 static void SyslogPacket (struct ip
*, int priority
, const char *label
);
109 static void SetAliasAddressFromIfName (const char *ifName
);
110 static void InitiateShutdown (int);
111 static void Shutdown (int);
112 static void RefreshAddr (int);
113 static void ParseOption (const char* option
, const char* parms
);
114 static void ReadConfigFile (const char* fileName
);
115 static void SetupPortRedirect (const char* parms
);
116 static void SetupProtoRedirect(const char* parms
);
117 static void SetupAddressRedirect (const char* parms
);
118 static void StrToAddr (const char* str
, struct in_addr
* addr
);
119 static u_short
StrToPort (const char* str
, const char* proto
);
120 static int StrToPortRange (const char* str
, const char* proto
, port_range
*portRange
);
121 static int StrToProto (const char* str
);
122 static int StrToAddrAndPortRange (const char* str
, struct in_addr
* addr
, char* proto
, port_range
*portRange
);
123 static void ParseArgs (int argc
, char** argv
);
124 static void FlushPacketBuffer (int fd
);
125 static void SetupPunchFW(const char *strValue
);
132 static int background
;
134 static int assignAliasAddr
;
137 static u_short inPort
;
138 static u_short outPort
;
139 static u_short inOutPort
;
140 static struct in_addr aliasAddr
;
141 static int dynamicMode
;
144 static int aliasOverhead
;
146 static char packetBuf
[IP_MAXPACKET
];
147 static int packetLen
;
148 static struct sockaddr_in packetAddr
;
149 static int packetSock
;
150 static int packetDirection
;
151 static int dropIgnoredIncoming
;
152 static int logDropped
;
153 static int logFacility
;
155 int main (int argc
, char** argv
)
161 struct sockaddr_in addr
;
166 * Initialize packet aliasing software.
167 * Done already here to be able to alter option bits
168 * during command line and configuration file processing.
183 aliasAddr
.s_addr
= INADDR_NONE
;
187 logFacility
= LOG_DAEMON
;
189 * Mark packet buffer empty.
192 packetDirection
= DONT_KNOW
;
194 ParseArgs (argc
, argv
);
196 * Open syslog channel.
198 openlog ("natd", LOG_CONS
| LOG_PID
| (verbose
? LOG_PERROR
: 0),
201 * Check that valid aliasing address has been given.
203 if (aliasAddr
.s_addr
== INADDR_NONE
&& ifName
== NULL
)
204 errx (1, "aliasing address not given");
207 * Check that valid port number is known.
209 if (inPort
!= 0 || outPort
!= 0)
210 if (inPort
== 0 || outPort
== 0)
211 errx (1, "both input and output ports are required");
213 if (inPort
== 0 && outPort
== 0 && inOutPort
== 0)
214 ParseOption ("port", DEFAULT_SERVICE
);
217 * Check if ignored packets should be dropped.
219 dropIgnoredIncoming
= PacketAliasSetMode (0, 0);
220 dropIgnoredIncoming
&= PKT_ALIAS_DENY_INCOMING
;
222 * Create divert sockets. Use only one socket if -p was specified
223 * on command line. Otherwise, create separate sockets for
224 * outgoing and incoming connnections.
228 divertInOut
= socket (PF_INET
, SOCK_RAW
, IPPROTO_DIVERT
);
229 if (divertInOut
== -1)
230 Quit ("Unable to create divert socket.");
238 addr
.sin_family
= AF_INET
;
239 addr
.sin_addr
.s_addr
= INADDR_ANY
;
240 addr
.sin_port
= inOutPort
;
242 if (bind (divertInOut
,
243 (struct sockaddr
*) &addr
,
245 Quit ("Unable to bind divert socket.");
249 divertIn
= socket (PF_INET
, SOCK_RAW
, IPPROTO_DIVERT
);
251 Quit ("Unable to create incoming divert socket.");
253 divertOut
= socket (PF_INET
, SOCK_RAW
, IPPROTO_DIVERT
);
255 Quit ("Unable to create outgoing divert socket.");
260 * Bind divert sockets.
263 addr
.sin_family
= AF_INET
;
264 addr
.sin_addr
.s_addr
= INADDR_ANY
;
265 addr
.sin_port
= inPort
;
268 (struct sockaddr
*) &addr
,
270 Quit ("Unable to bind incoming divert socket.");
272 addr
.sin_family
= AF_INET
;
273 addr
.sin_addr
.s_addr
= INADDR_ANY
;
274 addr
.sin_port
= outPort
;
277 (struct sockaddr
*) &addr
,
279 Quit ("Unable to bind outgoing divert socket.");
282 * Create routing socket if interface name specified and in dynamic mode.
288 routeSock
= socket (PF_ROUTE
, SOCK_RAW
, 0);
290 Quit ("Unable to create routing info socket.");
295 SetAliasAddressFromIfName (ifName
);
298 * Create socket for sending ICMP messages.
300 icmpSock
= socket (AF_INET
, SOCK_RAW
, IPPROTO_ICMP
);
302 Quit ("Unable to create ICMP socket.");
305 * And disable reads for the socket, otherwise it slowly fills
306 * up with received icmps which we do not use.
308 shutdown(icmpSock
, SHUT_RD
);
311 * Become a daemon unless verbose mode was requested.
316 * Catch signals to manage shutdown and
317 * refresh of interface address.
319 siginterrupt(SIGTERM
, 1);
320 siginterrupt(SIGHUP
, 1);
321 signal (SIGTERM
, InitiateShutdown
);
322 signal (SIGHUP
, RefreshAddr
);
324 * Set alias address if it has been given.
326 if (aliasAddr
.s_addr
!= INADDR_NONE
)
327 PacketAliasSetAddress (aliasAddr
);
329 * We need largest descriptor number for select.
334 if (divertIn
> fdMax
)
337 if (divertOut
> fdMax
)
340 if (divertInOut
> fdMax
)
343 if (routeSock
> fdMax
)
348 if (divertInOut
!= -1 && !ifName
&& packetSock
== -1) {
350 * When using only one socket, just call
351 * DoAliasing repeatedly to process packets.
353 DoAliasing (divertInOut
, DONT_KNOW
);
357 * Build read mask from socket descriptors to select.
360 FD_ZERO (&writeMask
);
363 * If there is unsent packet in buffer, use select
364 * to check when socket comes writable again.
366 if (packetSock
!= -1) {
368 FD_SET (packetSock
, &writeMask
);
372 * No unsent packet exists - safe to check if
373 * new ones are available.
376 FD_SET (divertIn
, &readMask
);
379 FD_SET (divertOut
, &readMask
);
381 if (divertInOut
!= -1)
382 FD_SET (divertInOut
, &readMask
);
385 * Routing info is processed always.
388 FD_SET (routeSock
, &readMask
);
390 if (select (fdMax
+ 1,
399 Quit ("Select failed.");
402 if (packetSock
!= -1)
403 if (FD_ISSET (packetSock
, &writeMask
))
404 FlushPacketBuffer (packetSock
);
407 if (FD_ISSET (divertIn
, &readMask
))
408 DoAliasing (divertIn
, INPUT
);
411 if (FD_ISSET (divertOut
, &readMask
))
412 DoAliasing (divertOut
, OUTPUT
);
414 if (divertInOut
!= -1)
415 if (FD_ISSET (divertInOut
, &readMask
))
416 DoAliasing (divertInOut
, DONT_KNOW
);
419 if (FD_ISSET (routeSock
, &readMask
))
420 HandleRoutingInfo (routeSock
);
429 static void DaemonMode ()
436 pidFile
= fopen (PIDFILE
, "w");
439 fprintf (pidFile
, "%d\n", getpid ());
444 static void ParseArgs (int argc
, char** argv
)
449 int len
; /* bounds checking */
451 for (arg
= 1; arg
< argc
; arg
++) {
456 warnx ("invalid option %s", opt
);
463 while (arg
< argc
- 1) {
465 if (argv
[arg
+ 1][0] == '-')
469 strncat (parmBuf
, " ", sizeof(parmBuf
) - (len
+ 1));
470 len
+= strlen(parmBuf
+ len
);
474 strncat (parmBuf
, argv
[arg
], sizeof(parmBuf
) - (len
+ 1));
475 len
+= strlen(parmBuf
+ len
);
479 ParseOption (opt
+ 1, (len
? parmBuf
: NULL
));
484 static void DoAliasing (int fd
, int direction
)
492 if (assignAliasAddr
) {
494 SetAliasAddressFromIfName (ifName
);
498 * Get packet from socket.
500 addrSize
= sizeof packetAddr
;
501 origBytes
= recvfrom (fd
,
505 (struct sockaddr
*) &packetAddr
,
508 if (origBytes
== -1) {
511 Warn ("read from divert socket failed");
516 * This is a IP packet.
518 ip
= (struct ip
*) packetBuf
;
519 if (direction
== DONT_KNOW
) {
520 if (packetAddr
.sin_addr
.s_addr
== INADDR_ANY
)
528 * Print packet direction and protocol type.
530 printf (direction
== OUTPUT
? "Out " : "In ");
546 printf ("[%d] ", ip
->ip_p
);
555 if (direction
== OUTPUT
) {
557 * Outgoing packets. Do aliasing.
559 PacketAliasOut (packetBuf
, IP_MAXPACKET
);
566 status
= PacketAliasIn (packetBuf
, IP_MAXPACKET
);
567 if (status
== PKT_ALIAS_IGNORED
&&
568 dropIgnoredIncoming
) {
571 printf (" dropped.\n");
574 SyslogPacket (ip
, LOG_WARNING
, "denied");
580 * Length might have changed during aliasing.
582 bytes
= ntohs (ip
->ip_len
);
584 * Update alias overhead size for outgoing packets.
586 if (direction
== OUTPUT
&&
587 bytes
- origBytes
> aliasOverhead
)
588 aliasOverhead
= bytes
- origBytes
;
593 * Print addresses after aliasing.
595 printf (" aliased to\n");
603 packetDirection
= direction
;
605 FlushPacketBuffer (fd
);
608 static void FlushPacketBuffer (int fd
)
613 * Put packet back for processing.
619 (struct sockaddr
*) &packetAddr
,
622 if (wrote
!= packetLen
) {
624 * If buffer space is not available,
625 * just return. Main loop will take care of
626 * retrying send when space becomes available.
628 if (errno
== ENOBUFS
)
631 if (errno
== EMSGSIZE
) {
633 if (packetDirection
== OUTPUT
&&
635 SendNeedFragIcmp (icmpSock
,
636 (struct ip
*) packetBuf
,
637 ifMTU
- aliasOverhead
);
641 sprintf (msgBuf
, "failed to write packet back");
649 static void HandleRoutingInfo (int fd
)
652 struct if_msghdr ifMsg
;
654 * Get packet from socket.
656 bytes
= read (fd
, &ifMsg
, sizeof ifMsg
);
659 Warn ("read from routing socket failed");
663 if (ifMsg
.ifm_version
!= RTM_VERSION
) {
665 Warn ("unexpected packet read from routing socket");
670 printf ("Routing message %#x received.\n", ifMsg
.ifm_type
);
672 if ((ifMsg
.ifm_type
== RTM_NEWADDR
|| ifMsg
.ifm_type
== RTM_IFINFO
) &&
673 ifMsg
.ifm_index
== ifIndex
) {
675 printf("Interface address/MTU has probably changed.\n");
680 static void PrintPacket (struct ip
* ip
)
682 printf ("%s", FormatPacket (ip
));
685 static void SyslogPacket (struct ip
* ip
, int priority
, const char *label
)
687 syslog (priority
, "%s %s", label
, FormatPacket (ip
));
690 static char* FormatPacket (struct ip
* ip
)
692 static char buf
[256];
693 struct tcphdr
* tcphdr
;
694 struct udphdr
* udphdr
;
695 struct icmp
* icmphdr
;
699 strcpy (src
, inet_ntoa (ip
->ip_src
));
700 strcpy (dst
, inet_ntoa (ip
->ip_dst
));
704 tcphdr
= (struct tcphdr
*) ((char*) ip
+ (ip
->ip_hl
<< 2));
705 sprintf (buf
, "[TCP] %s:%d -> %s:%d",
707 ntohs (tcphdr
->th_sport
),
709 ntohs (tcphdr
->th_dport
));
713 udphdr
= (struct udphdr
*) ((char*) ip
+ (ip
->ip_hl
<< 2));
714 sprintf (buf
, "[UDP] %s:%d -> %s:%d",
716 ntohs (udphdr
->uh_sport
),
718 ntohs (udphdr
->uh_dport
));
722 icmphdr
= (struct icmp
*) ((char*) ip
+ (ip
->ip_hl
<< 2));
723 sprintf (buf
, "[ICMP] %s -> %s %u(%u)",
731 sprintf (buf
, "[%d] %s -> %s ", ip
->ip_p
, src
, dst
);
739 SetAliasAddressFromIfName(const char *ifn
)
743 char *buf
, *lim
, *next
;
744 struct if_msghdr
*ifm
;
745 struct ifa_msghdr
*ifam
;
746 struct sockaddr_dl
*sdl
;
747 struct sockaddr_in
*sin
;
752 mib
[3] = AF_INET
; /* Only IP addresses please */
753 mib
[4] = NET_RT_IFLIST
;
754 mib
[5] = 0; /* ifIndex??? */
756 * Get interface data.
758 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) == -1)
759 err(1, "iflist-sysctl-estimate");
760 if ((buf
= malloc(needed
)) == NULL
)
761 errx(1, "malloc failed");
762 if (sysctl(mib
, 6, buf
, &needed
, NULL
, 0) == -1)
763 err(1, "iflist-sysctl-get");
766 * Loop through interfaces until one with
767 * given name is found. This is done to
768 * find correct interface index for routing
769 * message processing.
774 ifm
= (struct if_msghdr
*)next
;
775 next
+= ifm
->ifm_msglen
;
776 if (ifm
->ifm_version
!= RTM_VERSION
) {
778 warnx("routing message version %d "
779 "not understood", ifm
->ifm_version
);
782 if (ifm
->ifm_type
== RTM_IFINFO
) {
783 sdl
= (struct sockaddr_dl
*)(ifm
+ 1);
784 if (strlen(ifn
) == sdl
->sdl_nlen
&&
785 strncmp(ifn
, sdl
->sdl_data
, sdl
->sdl_nlen
) == 0) {
786 ifIndex
= ifm
->ifm_index
;
787 ifMTU
= ifm
->ifm_data
.ifi_mtu
;
789 PacketAliasClampMSS(ifMTU
- sizeof(struct tcphdr
) - sizeof(struct ip
));
795 errx(1, "unknown interface name %s", ifn
);
797 * Get interface address.
799 if (aliasAddr
.s_addr
== INADDR_NONE
) {
802 ifam
= (struct ifa_msghdr
*)next
;
803 next
+= ifam
->ifam_msglen
;
804 if (ifam
->ifam_version
!= RTM_VERSION
) {
806 warnx("routing message version %d "
807 "not understood", ifam
->ifam_version
);
810 if (ifam
->ifam_type
!= RTM_NEWADDR
)
812 if (ifam
->ifam_addrs
& RTA_IFA
) {
814 char *cp
= (char *)(ifam
+ 1);
817 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
818 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
820 for (i
= 1; i
< RTA_IFA
; i
<<= 1)
821 if (ifam
->ifam_addrs
& i
)
822 ADVANCE(cp
, (struct sockaddr
*)cp
);
823 if (((struct sockaddr
*)cp
)->sa_family
== AF_INET
) {
824 sin
= (struct sockaddr_in
*)cp
;
830 errx(1, "%s: cannot get interface address", ifn
);
832 PacketAliasSetAddress(sin
->sin_addr
);
833 syslog(LOG_INFO
, "Aliasing to %s, mtu %d bytes",
834 inet_ntoa(sin
->sin_addr
), ifMTU
);
840 void Quit (const char* msg
)
846 void Warn (const char* msg
)
849 syslog (LOG_ALERT
, "%s (%m)", msg
);
854 static void RefreshAddr (int sig
)
860 static void InitiateShutdown (int sig
)
863 * Start timer to allow kernel gracefully
864 * shutdown existing connections when system
867 siginterrupt(SIGALRM
, 1);
868 signal (SIGALRM
, Shutdown
);
872 static void Shutdown (int sig
)
878 * Different options recognized by this program.
914 * Option information structure (used by ParseOption).
922 const char* parmDescription
;
923 const char* description
;
925 const char* shortName
;
929 * Table of known options.
932 static struct OptionInfo optionTable
[] = {
935 PKT_ALIAS_UNREGISTERED_ONLY
,
938 "alias only unregistered addresses",
951 PKT_ALIAS_PROXY_ONLY
,
962 "operate in reverse mode",
967 PKT_ALIAS_DENY_INCOMING
,
970 "allow incoming connections",
975 PKT_ALIAS_USE_SOCKETS
,
978 "use sockets to inhibit port conflict",
983 PKT_ALIAS_SAME_PORTS
,
986 "try to keep original port numbers for connections",
994 "verbose mode, dump packet information",
1002 "dynamic mode, automatically detect interface address changes",
1010 "enable TCP MSS clamping",
1017 "number|service_name",
1018 "set port for incoming packets",
1025 "number|service_name",
1026 "set port for outgoing packets",
1033 "number|service_name",
1034 "set port (defaults to natd/divert)",
1042 "address to use for aliasing",
1050 "address to use for incoming sessions",
1058 "take aliasing address from interface",
1065 "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
1067 "add transparent proxying / destination NAT",
1074 "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
1075 " [remote_addr[:remote_port_range]]",
1076 "redirect a port (or ports) for incoming traffic",
1083 "proto local_addr [public_addr] [remote_addr]",
1084 "redirect packets of a given proto",
1091 "local_addr[,...] public_addr",
1092 "define mapping between local and public addresses",
1100 "read options from configuration file",
1108 "enable logging of denied incoming packets",
1116 "name of syslog facility to use for logging",
1124 "punch holes in the firewall for incoming FTP/IRC DCC connections",
1129 static void ParseOption (const char* option
, const char* parms
)
1132 struct OptionInfo
* info
;
1137 const char* strValue
;
1138 struct in_addr addrValue
;
1141 CODE
* fac_record
= NULL
;
1143 * Find option from table.
1145 max
= sizeof (optionTable
) / sizeof (struct OptionInfo
);
1146 for (i
= 0, info
= optionTable
; i
< max
; i
++, info
++) {
1148 if (!strcmp (info
->name
, option
))
1151 if (info
->shortName
)
1152 if (!strcmp (info
->shortName
, option
))
1158 warnx ("unknown option %s", option
);
1169 switch (info
->parm
) {
1174 if (!strcmp (parms
, "yes"))
1177 if (!strcmp (parms
, "no"))
1180 errx (1, "%s needs yes/no parameter", option
);
1185 errx (1, "%s needs service name or "
1186 "port number parameter",
1189 uNumValue
= StrToPort (parms
, "divert");
1194 numValue
= strtol (parms
, &end
, 10);
1199 errx (1, "%s needs numeric parameter", option
);
1205 errx (1, "%s needs parameter", option
);
1210 errx (1, "%s does not take parameters", option
);
1215 errx (1, "%s needs address/host parameter", option
);
1217 StrToAddr (parms
, &addrValue
);
1221 switch (info
->type
) {
1222 case PacketAliasOption
:
1224 aliasValue
= yesNoValue
? info
->packetAliasOpt
: 0;
1225 PacketAliasSetMode (aliasValue
, info
->packetAliasOpt
);
1229 verbose
= yesNoValue
;
1233 dynamicMode
= yesNoValue
;
1237 clampMSS
= yesNoValue
;
1245 outPort
= uNumValue
;
1249 inOutPort
= uNumValue
;
1253 memcpy (&aliasAddr
, &addrValue
, sizeof (struct in_addr
));
1257 PacketAliasSetTarget(addrValue
);
1261 SetupPortRedirect (strValue
);
1265 SetupProtoRedirect(strValue
);
1268 case RedirectAddress
:
1269 SetupAddressRedirect (strValue
);
1273 PacketAliasProxyRule (strValue
);
1280 ifName
= strdup (strValue
);
1284 ReadConfigFile (strValue
);
1293 fac_record
= facilitynames
;
1294 while (fac_record
->c_name
!= NULL
) {
1296 if (!strcmp (fac_record
->c_name
, strValue
)) {
1298 logFacility
= fac_record
->c_val
;
1306 if(fac_record
->c_name
== NULL
)
1307 errx(1, "Unknown log facility name: %s", strValue
);
1312 SetupPunchFW(strValue
);
1317 void ReadConfigFile (const char* fileName
)
1325 file
= fopen (fileName
, "r");
1327 err(1, "cannot open config file %s", fileName
);
1329 while ((buf
= fgetln(file
, &len
)) != NULL
) {
1330 if (buf
[len
- 1] == '\n')
1331 buf
[len
- 1] = '\0';
1333 errx(1, "config file format error: "
1334 "last line should end with newline");
1337 * Check for comments, strip off trailing spaces.
1339 if ((ptr
= strchr(buf
, '#')))
1341 for (ptr
= buf
; isspace(*ptr
); ++ptr
)
1345 for (p
= strchr(buf
, '\0'); isspace(*--p
);)
1350 * Extract option name.
1353 while (*ptr
&& !isspace (*ptr
))
1362 * Skip white space between name and parms.
1364 while (*ptr
&& isspace (*ptr
))
1367 ParseOption (option
, *ptr
? ptr
: NULL
);
1373 static void Usage ()
1377 struct OptionInfo
* info
;
1379 fprintf (stderr
, "Recognized options:\n\n");
1381 max
= sizeof (optionTable
) / sizeof (struct OptionInfo
);
1382 for (i
= 0, info
= optionTable
; i
< max
; i
++, info
++) {
1384 fprintf (stderr
, "-%-20s %s\n", info
->name
,
1385 info
->parmDescription
);
1387 if (info
->shortName
)
1388 fprintf (stderr
, "-%-20s %s\n", info
->shortName
,
1389 info
->parmDescription
);
1391 fprintf (stderr
, " %s\n\n", info
->description
);
1397 void SetupPortRedirect (const char* parms
)
1402 struct in_addr localAddr
;
1403 struct in_addr publicAddr
;
1404 struct in_addr remoteAddr
;
1405 port_range portRange
;
1406 u_short localPort
= 0;
1407 u_short publicPort
= 0;
1408 u_short remotePort
= 0;
1409 u_short numLocalPorts
= 0;
1410 u_short numPublicPorts
= 0;
1411 u_short numRemotePorts
= 0;
1416 struct alias_link
*link
= NULL
;
1418 strcpy (buf
, parms
);
1422 protoName
= strtok (buf
, " \t");
1424 errx (1, "redirect_port: missing protocol");
1426 proto
= StrToProto (protoName
);
1428 * Extract local address.
1430 ptr
= strtok (NULL
, " \t");
1432 errx (1, "redirect_port: missing local address");
1434 separator
= strchr(ptr
, ',');
1435 if (separator
) { /* LSNAT redirection syntax. */
1436 localAddr
.s_addr
= INADDR_NONE
;
1441 if ( StrToAddrAndPortRange (ptr
, &localAddr
, protoName
, &portRange
) != 0 )
1442 errx (1, "redirect_port: invalid local port range");
1444 localPort
= GETLOPORT(portRange
);
1445 numLocalPorts
= GETNUMPORTS(portRange
);
1450 * Extract public port and optionally address.
1452 ptr
= strtok (NULL
, " \t");
1454 errx (1, "redirect_port: missing public port");
1456 separator
= strchr (ptr
, ':');
1458 if (StrToAddrAndPortRange (ptr
, &publicAddr
, protoName
, &portRange
) != 0 )
1459 errx (1, "redirect_port: invalid public port range");
1462 publicAddr
.s_addr
= INADDR_ANY
;
1463 if (StrToPortRange (ptr
, protoName
, &portRange
) != 0)
1464 errx (1, "redirect_port: invalid public port range");
1467 publicPort
= GETLOPORT(portRange
);
1468 numPublicPorts
= GETNUMPORTS(portRange
);
1471 * Extract remote address and optionally port.
1473 ptr
= strtok (NULL
, " \t");
1475 separator
= strchr (ptr
, ':');
1477 if (StrToAddrAndPortRange (ptr
, &remoteAddr
, protoName
, &portRange
) != 0)
1478 errx (1, "redirect_port: invalid remote port range");
1480 SETLOPORT(portRange
, 0);
1481 SETNUMPORTS(portRange
, 1);
1482 StrToAddr (ptr
, &remoteAddr
);
1486 SETLOPORT(portRange
, 0);
1487 SETNUMPORTS(portRange
, 1);
1488 remoteAddr
.s_addr
= INADDR_ANY
;
1491 remotePort
= GETLOPORT(portRange
);
1492 numRemotePorts
= GETNUMPORTS(portRange
);
1495 * Make sure port ranges match up, then add the redirect ports.
1497 if (numLocalPorts
!= numPublicPorts
)
1498 errx (1, "redirect_port: port ranges must be equal in size");
1500 /* Remote port range is allowed to be '0' which means all ports. */
1501 if (numRemotePorts
!= numLocalPorts
&& (numRemotePorts
!= 1 || remotePort
!= 0))
1502 errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
1504 for (i
= 0 ; i
< numPublicPorts
; ++i
) {
1505 /* If remotePort is all ports, set it to 0. */
1506 u_short remotePortCopy
= remotePort
+ i
;
1507 if (numRemotePorts
== 1 && remotePort
== 0)
1510 link
= PacketAliasRedirectPort (localAddr
,
1511 htons(localPort
+ i
),
1513 htons(remotePortCopy
),
1515 htons(publicPort
+ i
),
1520 * Setup LSNAT server pool.
1522 if (serverPool
!= NULL
&& link
!= NULL
) {
1523 ptr
= strtok(serverPool
, ",");
1524 while (ptr
!= NULL
) {
1525 if (StrToAddrAndPortRange(ptr
, &localAddr
, protoName
, &portRange
) != 0)
1526 errx(1, "redirect_port: invalid local port range");
1528 localPort
= GETLOPORT(portRange
);
1529 if (GETNUMPORTS(portRange
) != 1)
1530 errx(1, "redirect_port: local port must be single in this context");
1531 PacketAliasAddServer(link
, localAddr
, htons(localPort
));
1532 ptr
= strtok(NULL
, ",");
1538 SetupProtoRedirect(const char* parms
)
1542 struct in_addr localAddr
;
1543 struct in_addr publicAddr
;
1544 struct in_addr remoteAddr
;
1547 struct protoent
*protoent
;
1549 strcpy (buf
, parms
);
1553 protoName
= strtok(buf
, " \t");
1555 errx(1, "redirect_proto: missing protocol");
1557 protoent
= getprotobyname(protoName
);
1558 if (protoent
== NULL
)
1559 errx(1, "redirect_proto: unknown protocol %s", protoName
);
1561 proto
= protoent
->p_proto
;
1563 * Extract local address.
1565 ptr
= strtok(NULL
, " \t");
1567 errx(1, "redirect_proto: missing local address");
1569 StrToAddr(ptr
, &localAddr
);
1571 * Extract optional public address.
1573 ptr
= strtok(NULL
, " \t");
1575 StrToAddr(ptr
, &publicAddr
);
1577 publicAddr
.s_addr
= INADDR_ANY
;
1579 * Extract optional remote address.
1581 ptr
= strtok(NULL
, " \t");
1583 StrToAddr(ptr
, &remoteAddr
);
1585 remoteAddr
.s_addr
= INADDR_ANY
;
1587 * Create aliasing link.
1589 (void)PacketAliasRedirectProto(localAddr
, remoteAddr
, publicAddr
,
1593 void SetupAddressRedirect (const char* parms
)
1598 struct in_addr localAddr
;
1599 struct in_addr publicAddr
;
1601 struct alias_link
*link
;
1603 strcpy (buf
, parms
);
1605 * Extract local address.
1607 ptr
= strtok (buf
, " \t");
1609 errx (1, "redirect_address: missing local address");
1611 separator
= strchr(ptr
, ',');
1612 if (separator
) { /* LSNAT redirection syntax. */
1613 localAddr
.s_addr
= INADDR_NONE
;
1616 StrToAddr (ptr
, &localAddr
);
1620 * Extract public address.
1622 ptr
= strtok (NULL
, " \t");
1624 errx (1, "redirect_address: missing public address");
1626 StrToAddr (ptr
, &publicAddr
);
1627 link
= PacketAliasRedirectAddr(localAddr
, publicAddr
);
1630 * Setup LSNAT server pool.
1632 if (serverPool
!= NULL
&& link
!= NULL
) {
1633 ptr
= strtok(serverPool
, ",");
1634 while (ptr
!= NULL
) {
1635 StrToAddr(ptr
, &localAddr
);
1636 PacketAliasAddServer(link
, localAddr
, htons(~0));
1637 ptr
= strtok(NULL
, ",");
1642 void StrToAddr (const char* str
, struct in_addr
* addr
)
1646 if (inet_aton (str
, addr
))
1649 hp
= gethostbyname (str
);
1651 errx (1, "unknown host %s", str
);
1653 memcpy (addr
, hp
->h_addr
, sizeof (struct in_addr
));
1656 u_short
StrToPort (const char* str
, const char* proto
)
1662 port
= strtol (str
, &end
, 10);
1664 return htons (port
);
1666 sp
= getservbyname (str
, proto
);
1668 errx (1, "unknown service %s/%s", str
, proto
);
1673 int StrToPortRange (const char* str
, const char* proto
, port_range
*portRange
)
1681 /* First see if this is a service, return corresponding port if so. */
1682 sp
= getservbyname (str
,proto
);
1684 SETLOPORT(*portRange
, ntohs(sp
->s_port
));
1685 SETNUMPORTS(*portRange
, 1);
1689 /* Not a service, see if it's a single port or port range. */
1690 sep
= strchr (str
, '-');
1692 SETLOPORT(*portRange
, strtol(str
, &end
, 10));
1695 SETNUMPORTS(*portRange
, 1);
1699 /* Error in port range field. */
1700 errx (1, "unknown service %s/%s", str
, proto
);
1703 /* Port range, get the values and sanity check. */
1704 sscanf (str
, "%hu-%hu", &loPort
, &hiPort
);
1705 SETLOPORT(*portRange
, loPort
);
1706 SETNUMPORTS(*portRange
, 0); /* Error by default */
1707 if (loPort
<= hiPort
)
1708 SETNUMPORTS(*portRange
, hiPort
- loPort
+ 1);
1710 if (GETNUMPORTS(*portRange
) == 0)
1711 errx (1, "invalid port range %s", str
);
1717 int StrToProto (const char* str
)
1719 if (!strcmp (str
, "tcp"))
1722 if (!strcmp (str
, "udp"))
1725 errx (1, "unknown protocol %s. Expected tcp or udp", str
);
1728 int StrToAddrAndPortRange (const char* str
, struct in_addr
* addr
, char* proto
, port_range
*portRange
)
1732 ptr
= strchr (str
, ':');
1734 errx (1, "%s is missing port number", str
);
1739 StrToAddr (str
, addr
);
1740 return StrToPortRange (ptr
, proto
, portRange
);
1744 SetupPunchFW(const char *strValue
)
1746 unsigned int base
, num
;
1748 if (sscanf(strValue
, "%u:%u", &base
, &num
) != 2)
1749 errx(1, "punch_fw: basenumber:count parameter required");
1751 PacketAliasSetFWBase(base
, num
);
1752 (void)PacketAliasSetMode(PKT_ALIAS_PUNCH_FW
, PKT_ALIAS_PUNCH_FW
);