2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * natd - Network Address Translation Daemon for FreeBSD.
25 * This software is provided free of charge, with no
26 * warranty of any kind, either expressed or implied.
27 * Use at your own risk.
29 * You may copy, modify and distribute this software (natd.c) freely.
31 * Ari Suutari <suutari@iki.fi>
34 * $FreeBSD: src/sbin/natd/natd.c,v 1.25.2.3 2000/07/11 20:00:57 ru Exp $
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <sys/sysctl.h>
44 #include <netinet/in.h>
45 #include <netinet/in_systm.h>
46 #include <netinet/ip.h>
47 #include <netinet/tcp.h>
48 #include <netinet/udp.h>
49 #include <netinet/ip_icmp.h>
51 #include <net/if_dl.h>
52 #include <net/route.h>
53 #include <arpa/inet.h>
70 * Default values for input and output
71 * divert socket ports.
74 #define DEFAULT_SERVICE "natd"
77 * Definition of a port range, and macros to deal with values.
78 * FORMAT: HI 16-bits == first port in range, 0 == all ports.
79 * LO 16-bits == number of ports in range
80 * NOTES: - Port values are not stored in network byte order.
83 typedef u_long port_range
;
85 #define GETLOPORT(x) ((x) >> 0x10)
86 #define GETNUMPORTS(x) ((x) & 0x0000ffff)
87 #define GETHIPORT(x) (GETLOPORT((x)) + GETNUMPORTS((x)))
89 /* Set y to be the low-port value in port_range variable x. */
90 #define SETLOPORT(x,y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
92 /* Set y to be the number of ports in port_range variable x. */
93 #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y))
96 * Function prototypes.
99 static void DoAliasing (int fd
, int direction
);
100 static void DaemonMode (void);
101 static void HandleRoutingInfo (int fd
);
102 static void Usage (void);
103 static char* FormatPacket (struct ip
*);
104 static void PrintPacket (struct ip
*);
105 static void SyslogPacket (struct ip
*, int priority
, const char *label
);
106 static void SetAliasAddressFromIfName (const char *ifName
);
107 static void InitiateShutdown (int);
108 static void Shutdown (int);
109 static void RefreshAddr (int);
110 static void ParseOption (const char* option
, const char* parms
);
111 static void ReadConfigFile (const char* fileName
);
112 static void SetupPortRedirect (const char* parms
);
113 static void SetupProtoRedirect(const char* parms
);
114 static void SetupAddressRedirect (const char* parms
);
115 static void StrToAddr (const char* str
, struct in_addr
* addr
);
116 static u_short
StrToPort (const char* str
, const char* proto
);
117 static int StrToPortRange (const char* str
, const char* proto
, port_range
*portRange
);
118 static int StrToProto (const char* str
);
119 static int StrToAddrAndPortRange (const char* str
, struct in_addr
* addr
, char* proto
, port_range
*portRange
);
120 static void ParseArgs (int argc
, char** argv
);
121 static void FlushPacketBuffer (int fd
);
122 static void SetupPunchFW(const char *strValue
);
129 static int background
;
131 static int assignAliasAddr
;
134 static u_short inPort
;
135 static u_short outPort
;
136 static u_short inOutPort
;
137 static struct in_addr aliasAddr
;
138 static int dynamicMode
;
140 static int aliasOverhead
;
142 static char packetBuf
[IP_MAXPACKET
];
143 static int packetLen
;
144 static struct sockaddr_in packetAddr
;
145 static int packetSock
;
146 static int packetDirection
;
147 static int dropIgnoredIncoming
;
148 static int logDropped
;
149 static int logFacility
;
151 int main (int argc
, char** argv
)
157 struct sockaddr_in addr
;
162 * Initialize packet aliasing software.
163 * Done already here to be able to alter option bits
164 * during command line and configuration file processing.
179 aliasAddr
.s_addr
= INADDR_NONE
;
183 logFacility
= LOG_DAEMON
;
185 * Mark packet buffer empty.
188 packetDirection
= DONT_KNOW
;
190 ParseArgs (argc
, argv
);
192 * Open syslog channel.
194 openlog ("natd", LOG_CONS
| LOG_PID
| (verbose
? LOG_PERROR
: 0),
197 * Check that valid aliasing address has been given.
199 if (aliasAddr
.s_addr
== INADDR_NONE
&& ifName
== NULL
)
200 errx (1, "aliasing address not given");
202 if (aliasAddr
.s_addr
!= INADDR_NONE
&& ifName
!= NULL
)
203 errx (1, "both alias address and interface "
204 "name are not allowed");
206 * Check that valid port number is known.
208 if (inPort
!= 0 || outPort
!= 0)
209 if (inPort
== 0 || outPort
== 0)
210 errx (1, "both input and output ports are required");
212 if (inPort
== 0 && outPort
== 0 && inOutPort
== 0)
213 ParseOption ("port", DEFAULT_SERVICE
);
216 * Check if ignored packets should be dropped.
218 dropIgnoredIncoming
= PacketAliasSetMode (0, 0);
219 dropIgnoredIncoming
&= PKT_ALIAS_DENY_INCOMING
;
221 * Create divert sockets. Use only one socket if -p was specified
222 * on command line. Otherwise, create separate sockets for
223 * outgoing and incoming connnections.
227 divertInOut
= socket (PF_INET
, SOCK_RAW
, IPPROTO_DIVERT
);
228 if (divertInOut
== -1)
229 Quit ("Unable to create divert socket.");
237 addr
.sin_family
= AF_INET
;
238 addr
.sin_addr
.s_addr
= INADDR_ANY
;
239 addr
.sin_port
= inOutPort
;
241 if (bind (divertInOut
,
242 (struct sockaddr
*) &addr
,
244 Quit ("Unable to bind divert socket.");
248 divertIn
= socket (PF_INET
, SOCK_RAW
, IPPROTO_DIVERT
);
250 Quit ("Unable to create incoming divert socket.");
252 divertOut
= socket (PF_INET
, SOCK_RAW
, IPPROTO_DIVERT
);
254 Quit ("Unable to create outgoing divert socket.");
259 * Bind divert sockets.
262 addr
.sin_family
= AF_INET
;
263 addr
.sin_addr
.s_addr
= INADDR_ANY
;
264 addr
.sin_port
= inPort
;
267 (struct sockaddr
*) &addr
,
269 Quit ("Unable to bind incoming divert socket.");
271 addr
.sin_family
= AF_INET
;
272 addr
.sin_addr
.s_addr
= INADDR_ANY
;
273 addr
.sin_port
= outPort
;
276 (struct sockaddr
*) &addr
,
278 Quit ("Unable to bind outgoing divert socket.");
281 * Create routing socket if interface name specified and in dynamic mode.
287 routeSock
= socket (PF_ROUTE
, SOCK_RAW
, 0);
289 Quit ("Unable to create routing info socket.");
294 SetAliasAddressFromIfName (ifName
);
297 * Create socket for sending ICMP messages.
299 icmpSock
= socket (AF_INET
, SOCK_RAW
, IPPROTO_ICMP
);
301 Quit ("Unable to create ICMP socket.");
304 * And disable reads for the socket, otherwise it slowly fills
305 * up with received icmps which we do not use.
307 shutdown(icmpSock
, SHUT_RD
);
310 * Become a daemon unless verbose mode was requested.
315 * Catch signals to manage shutdown and
316 * refresh of interface address.
318 siginterrupt(SIGTERM
, 1);
319 siginterrupt(SIGHUP
, 1);
320 signal (SIGTERM
, InitiateShutdown
);
321 signal (SIGHUP
, RefreshAddr
);
323 * Set alias address if it has been given.
325 if (aliasAddr
.s_addr
!= INADDR_NONE
)
326 PacketAliasSetAddress (aliasAddr
);
328 * We need largest descriptor number for select.
333 if (divertIn
> fdMax
)
336 if (divertOut
> fdMax
)
339 if (divertInOut
> fdMax
)
342 if (routeSock
> fdMax
)
347 if (divertInOut
!= -1 && !ifName
&& packetSock
== -1) {
349 * When using only one socket, just call
350 * DoAliasing repeatedly to process packets.
352 DoAliasing (divertInOut
, DONT_KNOW
);
356 * Build read mask from socket descriptors to select.
359 FD_ZERO (&writeMask
);
362 * If there is unsent packet in buffer, use select
363 * to check when socket comes writable again.
365 if (packetSock
!= -1) {
367 FD_SET (packetSock
, &writeMask
);
371 * No unsent packet exists - safe to check if
372 * new ones are available.
375 FD_SET (divertIn
, &readMask
);
378 FD_SET (divertOut
, &readMask
);
380 if (divertInOut
!= -1)
381 FD_SET (divertInOut
, &readMask
);
384 * Routing info is processed always.
387 FD_SET (routeSock
, &readMask
);
389 if (select (fdMax
+ 1,
398 Quit ("Select failed.");
401 if (packetSock
!= -1)
402 if (FD_ISSET (packetSock
, &writeMask
))
403 FlushPacketBuffer (packetSock
);
406 if (FD_ISSET (divertIn
, &readMask
))
407 DoAliasing (divertIn
, INPUT
);
410 if (FD_ISSET (divertOut
, &readMask
))
411 DoAliasing (divertOut
, OUTPUT
);
413 if (divertInOut
!= -1)
414 if (FD_ISSET (divertInOut
, &readMask
))
415 DoAliasing (divertInOut
, DONT_KNOW
);
418 if (FD_ISSET (routeSock
, &readMask
))
419 HandleRoutingInfo (routeSock
);
428 static void DaemonMode ()
435 pidFile
= fopen (PIDFILE
, "w");
438 fprintf (pidFile
, "%d\n", getpid ());
443 static void ParseArgs (int argc
, char** argv
)
448 int len
; /* bounds checking */
450 for (arg
= 1; arg
< argc
; arg
++) {
455 warnx ("invalid option %s", opt
);
462 while (arg
< argc
- 1) {
464 if (argv
[arg
+ 1][0] == '-')
468 strncat (parmBuf
, " ", sizeof(parmBuf
) - (len
+ 1));
469 len
+= strlen(parmBuf
+ len
);
473 strncat (parmBuf
, argv
[arg
], sizeof(parmBuf
) - (len
+ 1));
474 len
+= strlen(parmBuf
+ len
);
478 ParseOption (opt
+ 1, (len
? parmBuf
: NULL
));
483 static void DoAliasing (int fd
, int direction
)
491 if (assignAliasAddr
) {
493 SetAliasAddressFromIfName (ifName
);
497 * Get packet from socket.
499 addrSize
= sizeof packetAddr
;
500 origBytes
= recvfrom (fd
,
504 (struct sockaddr
*) &packetAddr
,
507 if (origBytes
== -1) {
510 Warn ("read from divert socket failed");
515 * This is a IP packet.
517 ip
= (struct ip
*) packetBuf
;
518 if (direction
== DONT_KNOW
) {
519 if (packetAddr
.sin_addr
.s_addr
== INADDR_ANY
)
527 * Print packet direction and protocol type.
529 printf (direction
== OUTPUT
? "Out " : "In ");
545 printf ("[%d] ", ip
->ip_p
);
554 if (direction
== OUTPUT
) {
556 * Outgoing packets. Do aliasing.
558 PacketAliasOut (packetBuf
, IP_MAXPACKET
);
565 status
= PacketAliasIn (packetBuf
, IP_MAXPACKET
);
566 if (status
== PKT_ALIAS_IGNORED
&&
567 dropIgnoredIncoming
) {
570 printf (" dropped.\n");
573 SyslogPacket (ip
, LOG_WARNING
, "denied");
579 * Length might have changed during aliasing.
581 bytes
= ntohs (ip
->ip_len
);
583 * Update alias overhead size for outgoing packets.
585 if (direction
== OUTPUT
&&
586 bytes
- origBytes
> aliasOverhead
)
587 aliasOverhead
= bytes
- origBytes
;
592 * Print addresses after aliasing.
594 printf (" aliased to\n");
602 packetDirection
= direction
;
604 FlushPacketBuffer (fd
);
607 static void FlushPacketBuffer (int fd
)
612 * Put packet back for processing.
618 (struct sockaddr
*) &packetAddr
,
621 if (wrote
!= packetLen
) {
623 * If buffer space is not available,
624 * just return. Main loop will take care of
625 * retrying send when space becomes available.
627 if (errno
== ENOBUFS
)
630 if (errno
== EMSGSIZE
) {
632 if (packetDirection
== OUTPUT
&&
634 SendNeedFragIcmp (icmpSock
,
635 (struct ip
*) packetBuf
,
636 ifMTU
- aliasOverhead
);
640 sprintf (msgBuf
, "failed to write packet back");
648 static void HandleRoutingInfo (int fd
)
651 struct if_msghdr ifMsg
;
653 * Get packet from socket.
655 bytes
= read (fd
, &ifMsg
, sizeof ifMsg
);
658 Warn ("read from routing socket failed");
662 if (ifMsg
.ifm_version
!= RTM_VERSION
) {
664 Warn ("unexpected packet read from routing socket");
669 printf ("Routing message %#x received.\n", ifMsg
.ifm_type
);
671 if ((ifMsg
.ifm_type
== RTM_NEWADDR
|| ifMsg
.ifm_type
== RTM_IFINFO
) &&
672 ifMsg
.ifm_index
== ifIndex
) {
674 printf("Interface address/MTU has probably changed.\n");
679 static void PrintPacket (struct ip
* ip
)
681 printf ("%s", FormatPacket (ip
));
684 static void SyslogPacket (struct ip
* ip
, int priority
, const char *label
)
686 syslog (priority
, "%s %s", label
, FormatPacket (ip
));
689 static char* FormatPacket (struct ip
* ip
)
691 static char buf
[256];
692 struct tcphdr
* tcphdr
;
693 struct udphdr
* udphdr
;
694 struct icmp
* icmphdr
;
698 strcpy (src
, inet_ntoa (ip
->ip_src
));
699 strcpy (dst
, inet_ntoa (ip
->ip_dst
));
703 tcphdr
= (struct tcphdr
*) ((char*) ip
+ (ip
->ip_hl
<< 2));
704 sprintf (buf
, "[TCP] %s:%d -> %s:%d",
706 ntohs (tcphdr
->th_sport
),
708 ntohs (tcphdr
->th_dport
));
712 udphdr
= (struct udphdr
*) ((char*) ip
+ (ip
->ip_hl
<< 2));
713 sprintf (buf
, "[UDP] %s:%d -> %s:%d",
715 ntohs (udphdr
->uh_sport
),
717 ntohs (udphdr
->uh_dport
));
721 icmphdr
= (struct icmp
*) ((char*) ip
+ (ip
->ip_hl
<< 2));
722 sprintf (buf
, "[ICMP] %s -> %s %u(%u)",
730 sprintf (buf
, "[%d] %s -> %s ", ip
->ip_p
, src
, dst
);
738 SetAliasAddressFromIfName(const char *ifn
)
742 char *buf
, *lim
, *next
;
743 struct if_msghdr
*ifm
;
744 struct ifa_msghdr
*ifam
;
745 struct sockaddr_dl
*sdl
;
746 struct sockaddr_in
*sin
;
751 mib
[3] = AF_INET
; /* Only IP addresses please */
752 mib
[4] = NET_RT_IFLIST
;
753 mib
[5] = 0; /* ifIndex??? */
755 * Get interface data.
757 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) == -1)
758 err(1, "iflist-sysctl-estimate");
759 if ((buf
= malloc(needed
)) == NULL
)
760 errx(1, "malloc failed");
761 if (sysctl(mib
, 6, buf
, &needed
, NULL
, 0) == -1)
762 err(1, "iflist-sysctl-get");
765 * Loop through interfaces until one with
766 * given name is found. This is done to
767 * find correct interface index for routing
768 * message processing.
773 ifm
= (struct if_msghdr
*)next
;
774 next
+= ifm
->ifm_msglen
;
775 if (ifm
->ifm_version
!= RTM_VERSION
) {
777 warnx("routing message version %d "
778 "not understood", ifm
->ifm_version
);
781 if (ifm
->ifm_type
== RTM_IFINFO
) {
782 sdl
= (struct sockaddr_dl
*)(ifm
+ 1);
783 if (strlen(ifn
) == sdl
->sdl_nlen
&&
784 strncmp(ifn
, sdl
->sdl_data
, sdl
->sdl_nlen
) == 0) {
785 ifIndex
= ifm
->ifm_index
;
786 ifMTU
= ifm
->ifm_data
.ifi_mtu
;
792 errx(1, "unknown interface name %s", ifn
);
794 * Get interface address.
798 ifam
= (struct ifa_msghdr
*)next
;
799 next
+= ifam
->ifam_msglen
;
800 if (ifam
->ifam_version
!= RTM_VERSION
) {
802 warnx("routing message version %d "
803 "not understood", ifam
->ifam_version
);
806 if (ifam
->ifam_type
!= RTM_NEWADDR
)
808 if (ifam
->ifam_addrs
& RTA_IFA
) {
810 char *cp
= (char *)(ifam
+ 1);
813 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
814 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
816 for (i
= 1; i
< RTA_IFA
; i
<<= 1)
817 if (ifam
->ifam_addrs
& i
)
818 ADVANCE(cp
, (struct sockaddr
*)cp
);
819 if (((struct sockaddr
*)cp
)->sa_family
== AF_INET
) {
820 sin
= (struct sockaddr_in
*)cp
;
826 errx(1, "%s: cannot get interface address", ifn
);
828 PacketAliasSetAddress(sin
->sin_addr
);
829 syslog(LOG_INFO
, "Aliasing to %s, mtu %d bytes",
830 inet_ntoa(sin
->sin_addr
), ifMTU
);
835 void Quit (const char* msg
)
841 void Warn (const char* msg
)
844 syslog (LOG_ALERT
, "%s (%m)", msg
);
849 static void RefreshAddr (int sig
)
855 static void InitiateShutdown (int sig
)
858 * Start timer to allow kernel gracefully
859 * shutdown existing connections when system
862 siginterrupt(SIGALRM
, 1);
863 signal (SIGALRM
, Shutdown
);
867 static void Shutdown (int sig
)
873 * Different options recognized by this program.
908 * Option information structure (used by ParseOption).
916 const char* parmDescription
;
917 const char* description
;
919 const char* shortName
;
923 * Table of known options.
926 static struct OptionInfo optionTable
[] = {
929 PKT_ALIAS_UNREGISTERED_ONLY
,
932 "alias only unregistered addresses",
945 PKT_ALIAS_PROXY_ONLY
,
956 "operate in reverse mode",
961 PKT_ALIAS_DENY_INCOMING
,
964 "allow incoming connections",
969 PKT_ALIAS_USE_SOCKETS
,
972 "use sockets to inhibit port conflict",
977 PKT_ALIAS_SAME_PORTS
,
980 "try to keep original port numbers for connections",
988 "verbose mode, dump packet information",
996 "dynamic mode, automatically detect interface address changes",
1003 "number|service_name",
1004 "set port for incoming packets",
1011 "number|service_name",
1012 "set port for outgoing packets",
1019 "number|service_name",
1020 "set port (defaults to natd/divert)",
1028 "address to use for aliasing",
1036 "address to use for incoming sessions",
1044 "take aliasing address from interface",
1051 "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
1053 "add transparent proxying / destination NAT",
1060 "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
1061 " [remote_addr[:remote_port_range]]",
1062 "redirect a port (or ports) for incoming traffic",
1069 "proto local_addr [public_addr] [remote_addr]",
1070 "redirect packets of a given proto",
1077 "local_addr[,...] public_addr",
1078 "define mapping between local and public addresses",
1086 "read options from configuration file",
1094 "enable logging of denied incoming packets",
1102 "name of syslog facility to use for logging",
1110 "punch holes in the firewall for incoming FTP/IRC DCC connections",
1115 static void ParseOption (const char* option
, const char* parms
)
1118 struct OptionInfo
* info
;
1123 const char* strValue
;
1124 struct in_addr addrValue
;
1127 CODE
* fac_record
= NULL
;
1129 * Find option from table.
1131 max
= sizeof (optionTable
) / sizeof (struct OptionInfo
);
1132 for (i
= 0, info
= optionTable
; i
< max
; i
++, info
++) {
1134 if (!strcmp (info
->name
, option
))
1137 if (info
->shortName
)
1138 if (!strcmp (info
->shortName
, option
))
1144 warnx ("unknown option %s", option
);
1155 switch (info
->parm
) {
1160 if (!strcmp (parms
, "yes"))
1163 if (!strcmp (parms
, "no"))
1166 errx (1, "%s needs yes/no parameter", option
);
1171 errx (1, "%s needs service name or "
1172 "port number parameter",
1175 uNumValue
= StrToPort (parms
, "divert");
1180 numValue
= strtol (parms
, &end
, 10);
1185 errx (1, "%s needs numeric parameter", option
);
1191 errx (1, "%s needs parameter", option
);
1196 errx (1, "%s does not take parameters", option
);
1201 errx (1, "%s needs address/host parameter", option
);
1203 StrToAddr (parms
, &addrValue
);
1207 switch (info
->type
) {
1208 case PacketAliasOption
:
1210 aliasValue
= yesNoValue
? info
->packetAliasOpt
: 0;
1211 PacketAliasSetMode (aliasValue
, info
->packetAliasOpt
);
1215 verbose
= yesNoValue
;
1219 dynamicMode
= yesNoValue
;
1227 outPort
= uNumValue
;
1231 inOutPort
= uNumValue
;
1235 memcpy (&aliasAddr
, &addrValue
, sizeof (struct in_addr
));
1239 PacketAliasSetTarget(addrValue
);
1243 SetupPortRedirect (strValue
);
1247 SetupProtoRedirect(strValue
);
1250 case RedirectAddress
:
1251 SetupAddressRedirect (strValue
);
1255 PacketAliasProxyRule (strValue
);
1262 ifName
= strdup (strValue
);
1266 ReadConfigFile (strValue
);
1275 fac_record
= facilitynames
;
1276 while (fac_record
->c_name
!= NULL
) {
1278 if (!strcmp (fac_record
->c_name
, strValue
)) {
1280 logFacility
= fac_record
->c_val
;
1288 if(fac_record
->c_name
== NULL
)
1289 errx(1, "Unknown log facility name: %s", strValue
);
1294 SetupPunchFW(strValue
);
1299 void ReadConfigFile (const char* fileName
)
1307 file
= fopen (fileName
, "r");
1309 err(1, "cannot open config file %s", fileName
);
1311 while ((buf
= fgetln(file
, &len
)) != NULL
) {
1312 if (buf
[len
- 1] == '\n')
1313 buf
[len
- 1] = '\0';
1315 errx(1, "config file format error: "
1316 "last line should end with newline");
1319 * Check for comments, strip off trailing spaces.
1321 if ((ptr
= strchr(buf
, '#')))
1323 for (ptr
= buf
; isspace(*ptr
); ++ptr
)
1327 for (p
= strchr(buf
, '\0'); isspace(*--p
);)
1332 * Extract option name.
1335 while (*ptr
&& !isspace (*ptr
))
1344 * Skip white space between name and parms.
1346 while (*ptr
&& isspace (*ptr
))
1349 ParseOption (option
, *ptr
? ptr
: NULL
);
1355 static void Usage ()
1359 struct OptionInfo
* info
;
1361 fprintf (stderr
, "Recognized options:\n\n");
1363 max
= sizeof (optionTable
) / sizeof (struct OptionInfo
);
1364 for (i
= 0, info
= optionTable
; i
< max
; i
++, info
++) {
1366 fprintf (stderr
, "-%-20s %s\n", info
->name
,
1367 info
->parmDescription
);
1369 if (info
->shortName
)
1370 fprintf (stderr
, "-%-20s %s\n", info
->shortName
,
1371 info
->parmDescription
);
1373 fprintf (stderr
, " %s\n\n", info
->description
);
1379 void SetupPortRedirect (const char* parms
)
1384 struct in_addr localAddr
;
1385 struct in_addr publicAddr
;
1386 struct in_addr remoteAddr
;
1387 port_range portRange
;
1388 u_short localPort
= 0;
1389 u_short publicPort
= 0;
1390 u_short remotePort
= 0;
1391 u_short numLocalPorts
= 0;
1392 u_short numPublicPorts
= 0;
1393 u_short numRemotePorts
= 0;
1398 struct alias_link
*link
= NULL
;
1400 strcpy (buf
, parms
);
1404 protoName
= strtok (buf
, " \t");
1406 errx (1, "redirect_port: missing protocol");
1408 proto
= StrToProto (protoName
);
1410 * Extract local address.
1412 ptr
= strtok (NULL
, " \t");
1414 errx (1, "redirect_port: missing local address");
1416 separator
= strchr(ptr
, ',');
1417 if (separator
) { /* LSNAT redirection syntax. */
1418 localAddr
.s_addr
= INADDR_NONE
;
1423 if ( StrToAddrAndPortRange (ptr
, &localAddr
, protoName
, &portRange
) != 0 )
1424 errx (1, "redirect_port: invalid local port range");
1426 localPort
= GETLOPORT(portRange
);
1427 numLocalPorts
= GETNUMPORTS(portRange
);
1432 * Extract public port and optionally address.
1434 ptr
= strtok (NULL
, " \t");
1436 errx (1, "redirect_port: missing public port");
1438 separator
= strchr (ptr
, ':');
1440 if (StrToAddrAndPortRange (ptr
, &publicAddr
, protoName
, &portRange
) != 0 )
1441 errx (1, "redirect_port: invalid public port range");
1444 publicAddr
.s_addr
= INADDR_ANY
;
1445 if (StrToPortRange (ptr
, protoName
, &portRange
) != 0)
1446 errx (1, "redirect_port: invalid public port range");
1449 publicPort
= GETLOPORT(portRange
);
1450 numPublicPorts
= GETNUMPORTS(portRange
);
1453 * Extract remote address and optionally port.
1455 ptr
= strtok (NULL
, " \t");
1457 separator
= strchr (ptr
, ':');
1459 if (StrToAddrAndPortRange (ptr
, &remoteAddr
, protoName
, &portRange
) != 0)
1460 errx (1, "redirect_port: invalid remote port range");
1462 SETLOPORT(portRange
, 0);
1463 SETNUMPORTS(portRange
, 1);
1464 StrToAddr (ptr
, &remoteAddr
);
1468 SETLOPORT(portRange
, 0);
1469 SETNUMPORTS(portRange
, 1);
1470 remoteAddr
.s_addr
= INADDR_ANY
;
1473 remotePort
= GETLOPORT(portRange
);
1474 numRemotePorts
= GETNUMPORTS(portRange
);
1477 * Make sure port ranges match up, then add the redirect ports.
1479 if (numLocalPorts
!= numPublicPorts
)
1480 errx (1, "redirect_port: port ranges must be equal in size");
1482 /* Remote port range is allowed to be '0' which means all ports. */
1483 if (numRemotePorts
!= numLocalPorts
&& (numRemotePorts
!= 1 || remotePort
!= 0))
1484 errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
1486 for (i
= 0 ; i
< numPublicPorts
; ++i
) {
1487 /* If remotePort is all ports, set it to 0. */
1488 u_short remotePortCopy
= remotePort
+ i
;
1489 if (numRemotePorts
== 1 && remotePort
== 0)
1492 link
= PacketAliasRedirectPort (localAddr
,
1493 htons(localPort
+ i
),
1495 htons(remotePortCopy
),
1497 htons(publicPort
+ i
),
1502 * Setup LSNAT server pool.
1504 if (serverPool
!= NULL
&& link
!= NULL
) {
1505 ptr
= strtok(serverPool
, ",");
1506 while (ptr
!= NULL
) {
1507 if (StrToAddrAndPortRange(ptr
, &localAddr
, protoName
, &portRange
) != 0)
1508 errx(1, "redirect_port: invalid local port range");
1510 localPort
= GETLOPORT(portRange
);
1511 if (GETNUMPORTS(portRange
) != 1)
1512 errx(1, "redirect_port: local port must be single in this context");
1513 PacketAliasAddServer(link
, localAddr
, htons(localPort
));
1514 ptr
= strtok(NULL
, ",");
1520 SetupProtoRedirect(const char* parms
)
1524 struct in_addr localAddr
;
1525 struct in_addr publicAddr
;
1526 struct in_addr remoteAddr
;
1529 struct protoent
*protoent
;
1531 strcpy (buf
, parms
);
1535 protoName
= strtok(buf
, " \t");
1537 errx(1, "redirect_proto: missing protocol");
1539 protoent
= getprotobyname(protoName
);
1540 if (protoent
== NULL
)
1541 errx(1, "redirect_proto: unknown protocol %s", protoName
);
1543 proto
= protoent
->p_proto
;
1545 * Extract local address.
1547 ptr
= strtok(NULL
, " \t");
1549 errx(1, "redirect_proto: missing local address");
1551 StrToAddr(ptr
, &localAddr
);
1553 * Extract optional public address.
1555 ptr
= strtok(NULL
, " \t");
1557 StrToAddr(ptr
, &publicAddr
);
1559 publicAddr
.s_addr
= INADDR_ANY
;
1561 * Extract optional remote address.
1563 ptr
= strtok(NULL
, " \t");
1565 StrToAddr(ptr
, &remoteAddr
);
1567 remoteAddr
.s_addr
= INADDR_ANY
;
1569 * Create aliasing link.
1571 (void)PacketAliasRedirectProto(localAddr
, remoteAddr
, publicAddr
,
1575 void SetupAddressRedirect (const char* parms
)
1580 struct in_addr localAddr
;
1581 struct in_addr publicAddr
;
1583 struct alias_link
*link
;
1585 strcpy (buf
, parms
);
1587 * Extract local address.
1589 ptr
= strtok (buf
, " \t");
1591 errx (1, "redirect_address: missing local address");
1593 separator
= strchr(ptr
, ',');
1594 if (separator
) { /* LSNAT redirection syntax. */
1595 localAddr
.s_addr
= INADDR_NONE
;
1598 StrToAddr (ptr
, &localAddr
);
1602 * Extract public address.
1604 ptr
= strtok (NULL
, " \t");
1606 errx (1, "redirect_address: missing public address");
1608 StrToAddr (ptr
, &publicAddr
);
1609 link
= PacketAliasRedirectAddr(localAddr
, publicAddr
);
1612 * Setup LSNAT server pool.
1614 if (serverPool
!= NULL
&& link
!= NULL
) {
1615 ptr
= strtok(serverPool
, ",");
1616 while (ptr
!= NULL
) {
1617 StrToAddr(ptr
, &localAddr
);
1618 PacketAliasAddServer(link
, localAddr
, htons(~0));
1619 ptr
= strtok(NULL
, ",");
1624 void StrToAddr (const char* str
, struct in_addr
* addr
)
1628 if (inet_aton (str
, addr
))
1631 hp
= gethostbyname (str
);
1633 errx (1, "unknown host %s", str
);
1635 memcpy (addr
, hp
->h_addr
, sizeof (struct in_addr
));
1638 u_short
StrToPort (const char* str
, const char* proto
)
1644 port
= strtol (str
, &end
, 10);
1646 return htons (port
);
1648 sp
= getservbyname (str
, proto
);
1650 errx (1, "unknown service %s/%s", str
, proto
);
1655 int StrToPortRange (const char* str
, const char* proto
, port_range
*portRange
)
1663 /* First see if this is a service, return corresponding port if so. */
1664 sp
= getservbyname (str
,proto
);
1666 SETLOPORT(*portRange
, ntohs(sp
->s_port
));
1667 SETNUMPORTS(*portRange
, 1);
1671 /* Not a service, see if it's a single port or port range. */
1672 sep
= strchr (str
, '-');
1674 SETLOPORT(*portRange
, strtol(str
, &end
, 10));
1677 SETNUMPORTS(*portRange
, 1);
1681 /* Error in port range field. */
1682 errx (1, "unknown service %s/%s", str
, proto
);
1685 /* Port range, get the values and sanity check. */
1686 sscanf (str
, "%hu-%hu", &loPort
, &hiPort
);
1687 SETLOPORT(*portRange
, loPort
);
1688 SETNUMPORTS(*portRange
, 0); /* Error by default */
1689 if (loPort
<= hiPort
)
1690 SETNUMPORTS(*portRange
, hiPort
- loPort
+ 1);
1692 if (GETNUMPORTS(*portRange
) == 0)
1693 errx (1, "invalid port range %s", str
);
1699 int StrToProto (const char* str
)
1701 if (!strcmp (str
, "tcp"))
1704 if (!strcmp (str
, "udp"))
1707 errx (1, "unknown protocol %s. Expected tcp or udp", str
);
1710 int StrToAddrAndPortRange (const char* str
, struct in_addr
* addr
, char* proto
, port_range
*portRange
)
1714 ptr
= strchr (str
, ':');
1716 errx (1, "%s is missing port number", str
);
1721 StrToAddr (str
, addr
);
1722 return StrToPortRange (ptr
, proto
, portRange
);
1726 SetupPunchFW(const char *strValue
)
1728 unsigned int base
, num
;
1730 if (sscanf(strValue
, "%u:%u", &base
, &num
) != 2)
1731 errx(1, "punch_fw: basenumber:count parameter required");
1733 PacketAliasSetFWBase(base
, num
);
1734 (void)PacketAliasSetMode(PKT_ALIAS_PUNCH_FW
, PKT_ALIAS_PUNCH_FW
);