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
;
141 static int aliasOverhead
;
143 static char packetBuf
[IP_MAXPACKET
];
144 static int packetLen
;
145 static struct sockaddr_in packetAddr
;
146 static int packetSock
;
147 static int packetDirection
;
148 static int dropIgnoredIncoming
;
149 static int logDropped
;
150 static int logFacility
;
152 int main (int argc
, char** argv
)
158 struct sockaddr_in addr
;
163 * Initialize packet aliasing software.
164 * Done already here to be able to alter option bits
165 * during command line and configuration file processing.
180 aliasAddr
.s_addr
= INADDR_NONE
;
184 logFacility
= LOG_DAEMON
;
186 * Mark packet buffer empty.
189 packetDirection
= DONT_KNOW
;
191 ParseArgs (argc
, argv
);
193 * Open syslog channel.
195 openlog ("natd", LOG_CONS
| LOG_PID
| (verbose
? LOG_PERROR
: 0),
198 * Check that valid aliasing address has been given.
200 if (aliasAddr
.s_addr
== INADDR_NONE
&& ifName
== NULL
)
201 errx (1, "aliasing address not given");
204 * Check that valid port number is known.
206 if (inPort
!= 0 || outPort
!= 0)
207 if (inPort
== 0 || outPort
== 0)
208 errx (1, "both input and output ports are required");
210 if (inPort
== 0 && outPort
== 0 && inOutPort
== 0)
211 ParseOption ("port", DEFAULT_SERVICE
);
214 * Check if ignored packets should be dropped.
216 dropIgnoredIncoming
= PacketAliasSetMode (0, 0);
217 dropIgnoredIncoming
&= PKT_ALIAS_DENY_INCOMING
;
219 * Create divert sockets. Use only one socket if -p was specified
220 * on command line. Otherwise, create separate sockets for
221 * outgoing and incoming connnections.
225 divertInOut
= socket (PF_INET
, SOCK_RAW
, IPPROTO_DIVERT
);
226 if (divertInOut
== -1)
227 Quit ("Unable to create divert socket.");
235 addr
.sin_family
= AF_INET
;
236 addr
.sin_addr
.s_addr
= INADDR_ANY
;
237 addr
.sin_port
= inOutPort
;
239 if (bind (divertInOut
,
240 (struct sockaddr
*) &addr
,
242 Quit ("Unable to bind divert socket.");
246 divertIn
= socket (PF_INET
, SOCK_RAW
, IPPROTO_DIVERT
);
248 Quit ("Unable to create incoming divert socket.");
250 divertOut
= socket (PF_INET
, SOCK_RAW
, IPPROTO_DIVERT
);
252 Quit ("Unable to create outgoing divert socket.");
257 * Bind divert sockets.
260 addr
.sin_family
= AF_INET
;
261 addr
.sin_addr
.s_addr
= INADDR_ANY
;
262 addr
.sin_port
= inPort
;
265 (struct sockaddr
*) &addr
,
267 Quit ("Unable to bind incoming divert socket.");
269 addr
.sin_family
= AF_INET
;
270 addr
.sin_addr
.s_addr
= INADDR_ANY
;
271 addr
.sin_port
= outPort
;
274 (struct sockaddr
*) &addr
,
276 Quit ("Unable to bind outgoing divert socket.");
279 * Create routing socket if interface name specified and in dynamic mode.
285 routeSock
= socket (PF_ROUTE
, SOCK_RAW
, 0);
287 Quit ("Unable to create routing info socket.");
292 SetAliasAddressFromIfName (ifName
);
295 * Create socket for sending ICMP messages.
297 icmpSock
= socket (AF_INET
, SOCK_RAW
, IPPROTO_ICMP
);
299 Quit ("Unable to create ICMP socket.");
302 * And disable reads for the socket, otherwise it slowly fills
303 * up with received icmps which we do not use.
305 shutdown(icmpSock
, SHUT_RD
);
308 * Become a daemon unless verbose mode was requested.
313 * Catch signals to manage shutdown and
314 * refresh of interface address.
316 siginterrupt(SIGTERM
, 1);
317 siginterrupt(SIGHUP
, 1);
318 signal (SIGTERM
, InitiateShutdown
);
319 signal (SIGHUP
, RefreshAddr
);
321 * Set alias address if it has been given.
323 if (aliasAddr
.s_addr
!= INADDR_NONE
)
324 PacketAliasSetAddress (aliasAddr
);
326 * We need largest descriptor number for select.
331 if (divertIn
> fdMax
)
334 if (divertOut
> fdMax
)
337 if (divertInOut
> fdMax
)
340 if (routeSock
> fdMax
)
345 if (divertInOut
!= -1 && !ifName
&& packetSock
== -1) {
347 * When using only one socket, just call
348 * DoAliasing repeatedly to process packets.
350 DoAliasing (divertInOut
, DONT_KNOW
);
354 * Build read mask from socket descriptors to select.
357 FD_ZERO (&writeMask
);
360 * If there is unsent packet in buffer, use select
361 * to check when socket comes writable again.
363 if (packetSock
!= -1) {
365 FD_SET (packetSock
, &writeMask
);
369 * No unsent packet exists - safe to check if
370 * new ones are available.
373 FD_SET (divertIn
, &readMask
);
376 FD_SET (divertOut
, &readMask
);
378 if (divertInOut
!= -1)
379 FD_SET (divertInOut
, &readMask
);
382 * Routing info is processed always.
385 FD_SET (routeSock
, &readMask
);
387 if (select (fdMax
+ 1,
396 Quit ("Select failed.");
399 if (packetSock
!= -1)
400 if (FD_ISSET (packetSock
, &writeMask
))
401 FlushPacketBuffer (packetSock
);
404 if (FD_ISSET (divertIn
, &readMask
))
405 DoAliasing (divertIn
, INPUT
);
408 if (FD_ISSET (divertOut
, &readMask
))
409 DoAliasing (divertOut
, OUTPUT
);
411 if (divertInOut
!= -1)
412 if (FD_ISSET (divertInOut
, &readMask
))
413 DoAliasing (divertInOut
, DONT_KNOW
);
416 if (FD_ISSET (routeSock
, &readMask
))
417 HandleRoutingInfo (routeSock
);
426 static void DaemonMode ()
433 pidFile
= fopen (PIDFILE
, "w");
436 fprintf (pidFile
, "%d\n", getpid ());
441 static void ParseArgs (int argc
, char** argv
)
446 int len
; /* bounds checking */
448 for (arg
= 1; arg
< argc
; arg
++) {
453 warnx ("invalid option %s", opt
);
460 while (arg
< argc
- 1) {
462 if (argv
[arg
+ 1][0] == '-')
466 strncat (parmBuf
, " ", sizeof(parmBuf
) - (len
+ 1));
467 len
+= strlen(parmBuf
+ len
);
471 strncat (parmBuf
, argv
[arg
], sizeof(parmBuf
) - (len
+ 1));
472 len
+= strlen(parmBuf
+ len
);
476 ParseOption (opt
+ 1, (len
? parmBuf
: NULL
));
481 static void DoAliasing (int fd
, int direction
)
489 if (assignAliasAddr
) {
491 SetAliasAddressFromIfName (ifName
);
495 * Get packet from socket.
497 addrSize
= sizeof packetAddr
;
498 origBytes
= recvfrom (fd
,
502 (struct sockaddr
*) &packetAddr
,
505 if (origBytes
== -1) {
508 Warn ("read from divert socket failed");
513 * This is a IP packet.
515 ip
= (struct ip
*) packetBuf
;
516 if (direction
== DONT_KNOW
) {
517 if (packetAddr
.sin_addr
.s_addr
== INADDR_ANY
)
525 * Print packet direction and protocol type.
527 printf (direction
== OUTPUT
? "Out " : "In ");
543 printf ("[%d] ", ip
->ip_p
);
552 if (direction
== OUTPUT
) {
554 * Outgoing packets. Do aliasing.
556 PacketAliasOut (packetBuf
, IP_MAXPACKET
);
563 status
= PacketAliasIn (packetBuf
, IP_MAXPACKET
);
564 if (status
== PKT_ALIAS_IGNORED
&&
565 dropIgnoredIncoming
) {
568 printf (" dropped.\n");
571 SyslogPacket (ip
, LOG_WARNING
, "denied");
577 * Length might have changed during aliasing.
579 bytes
= ntohs (ip
->ip_len
);
581 * Update alias overhead size for outgoing packets.
583 if (direction
== OUTPUT
&&
584 bytes
- origBytes
> aliasOverhead
)
585 aliasOverhead
= bytes
- origBytes
;
590 * Print addresses after aliasing.
592 printf (" aliased to\n");
600 packetDirection
= direction
;
602 FlushPacketBuffer (fd
);
605 static void FlushPacketBuffer (int fd
)
610 * Put packet back for processing.
616 (struct sockaddr
*) &packetAddr
,
619 if (wrote
!= packetLen
) {
621 * If buffer space is not available,
622 * just return. Main loop will take care of
623 * retrying send when space becomes available.
625 if (errno
== ENOBUFS
)
628 if (errno
== EMSGSIZE
) {
630 if (packetDirection
== OUTPUT
&&
632 SendNeedFragIcmp (icmpSock
,
633 (struct ip
*) packetBuf
,
634 ifMTU
- aliasOverhead
);
638 sprintf (msgBuf
, "failed to write packet back");
646 static void HandleRoutingInfo (int fd
)
649 struct if_msghdr ifMsg
;
651 * Get packet from socket.
653 bytes
= read (fd
, &ifMsg
, sizeof ifMsg
);
656 Warn ("read from routing socket failed");
660 if (ifMsg
.ifm_version
!= RTM_VERSION
) {
662 Warn ("unexpected packet read from routing socket");
667 printf ("Routing message %#x received.\n", ifMsg
.ifm_type
);
669 if ((ifMsg
.ifm_type
== RTM_NEWADDR
|| ifMsg
.ifm_type
== RTM_IFINFO
) &&
670 ifMsg
.ifm_index
== ifIndex
) {
672 printf("Interface address/MTU has probably changed.\n");
677 static void PrintPacket (struct ip
* ip
)
679 printf ("%s", FormatPacket (ip
));
682 static void SyslogPacket (struct ip
* ip
, int priority
, const char *label
)
684 syslog (priority
, "%s %s", label
, FormatPacket (ip
));
687 static char* FormatPacket (struct ip
* ip
)
689 static char buf
[256];
690 struct tcphdr
* tcphdr
;
691 struct udphdr
* udphdr
;
692 struct icmp
* icmphdr
;
696 strcpy (src
, inet_ntoa (ip
->ip_src
));
697 strcpy (dst
, inet_ntoa (ip
->ip_dst
));
701 tcphdr
= (struct tcphdr
*) ((char*) ip
+ (ip
->ip_hl
<< 2));
702 sprintf (buf
, "[TCP] %s:%d -> %s:%d",
704 ntohs (tcphdr
->th_sport
),
706 ntohs (tcphdr
->th_dport
));
710 udphdr
= (struct udphdr
*) ((char*) ip
+ (ip
->ip_hl
<< 2));
711 sprintf (buf
, "[UDP] %s:%d -> %s:%d",
713 ntohs (udphdr
->uh_sport
),
715 ntohs (udphdr
->uh_dport
));
719 icmphdr
= (struct icmp
*) ((char*) ip
+ (ip
->ip_hl
<< 2));
720 sprintf (buf
, "[ICMP] %s -> %s %u(%u)",
728 sprintf (buf
, "[%d] %s -> %s ", ip
->ip_p
, src
, dst
);
736 SetAliasAddressFromIfName(const char *ifn
)
740 char *buf
, *lim
, *next
;
741 struct if_msghdr
*ifm
;
742 struct ifa_msghdr
*ifam
;
743 struct sockaddr_dl
*sdl
;
744 struct sockaddr_in
*sin
;
749 mib
[3] = AF_INET
; /* Only IP addresses please */
750 mib
[4] = NET_RT_IFLIST
;
751 mib
[5] = 0; /* ifIndex??? */
753 * Get interface data.
755 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) == -1)
756 err(1, "iflist-sysctl-estimate");
757 if ((buf
= malloc(needed
)) == NULL
)
758 errx(1, "malloc failed");
759 if (sysctl(mib
, 6, buf
, &needed
, NULL
, 0) == -1)
760 err(1, "iflist-sysctl-get");
763 * Loop through interfaces until one with
764 * given name is found. This is done to
765 * find correct interface index for routing
766 * message processing.
771 ifm
= (struct if_msghdr
*)next
;
772 next
+= ifm
->ifm_msglen
;
773 if (ifm
->ifm_version
!= RTM_VERSION
) {
775 warnx("routing message version %d "
776 "not understood", ifm
->ifm_version
);
779 if (ifm
->ifm_type
== RTM_IFINFO
) {
780 sdl
= (struct sockaddr_dl
*)(ifm
+ 1);
781 if (strlen(ifn
) == sdl
->sdl_nlen
&&
782 strncmp(ifn
, sdl
->sdl_data
, sdl
->sdl_nlen
) == 0) {
783 ifIndex
= ifm
->ifm_index
;
784 ifMTU
= ifm
->ifm_data
.ifi_mtu
;
786 PacketAliasClampMSS(ifMTU
- sizeof(struct tcphdr
) - sizeof(struct ip
));
792 errx(1, "unknown interface name %s", ifn
);
794 * Get interface address.
796 if (aliasAddr
.s_addr
== INADDR_NONE
) {
799 ifam
= (struct ifa_msghdr
*)next
;
800 next
+= ifam
->ifam_msglen
;
801 if (ifam
->ifam_version
!= RTM_VERSION
) {
803 warnx("routing message version %d "
804 "not understood", ifam
->ifam_version
);
807 if (ifam
->ifam_type
!= RTM_NEWADDR
)
809 if (ifam
->ifam_addrs
& RTA_IFA
) {
811 char *cp
= (char *)(ifam
+ 1);
814 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
815 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
817 for (i
= 1; i
< RTA_IFA
; i
<<= 1)
818 if (ifam
->ifam_addrs
& i
)
819 ADVANCE(cp
, (struct sockaddr
*)cp
);
820 if (((struct sockaddr
*)cp
)->sa_family
== AF_INET
) {
821 sin
= (struct sockaddr_in
*)cp
;
827 errx(1, "%s: cannot get interface address", ifn
);
829 PacketAliasSetAddress(sin
->sin_addr
);
830 syslog(LOG_INFO
, "Aliasing to %s, mtu %d bytes",
831 inet_ntoa(sin
->sin_addr
), ifMTU
);
837 void Quit (const char* msg
)
843 void Warn (const char* msg
)
846 syslog (LOG_ALERT
, "%s (%m)", msg
);
851 static void RefreshAddr (int sig
)
857 static void InitiateShutdown (int sig
)
860 * Start timer to allow kernel gracefully
861 * shutdown existing connections when system
864 siginterrupt(SIGALRM
, 1);
865 signal (SIGALRM
, Shutdown
);
869 static void Shutdown (int sig
)
875 * Different options recognized by this program.
911 * Option information structure (used by ParseOption).
919 const char* parmDescription
;
920 const char* description
;
922 const char* shortName
;
926 * Table of known options.
929 static struct OptionInfo optionTable
[] = {
932 PKT_ALIAS_UNREGISTERED_ONLY
,
935 "alias only unregistered addresses",
948 PKT_ALIAS_PROXY_ONLY
,
959 "operate in reverse mode",
964 PKT_ALIAS_DENY_INCOMING
,
967 "allow incoming connections",
972 PKT_ALIAS_USE_SOCKETS
,
975 "use sockets to inhibit port conflict",
980 PKT_ALIAS_SAME_PORTS
,
983 "try to keep original port numbers for connections",
991 "verbose mode, dump packet information",
999 "dynamic mode, automatically detect interface address changes",
1007 "enable TCP MSS clamping",
1014 "number|service_name",
1015 "set port for incoming packets",
1022 "number|service_name",
1023 "set port for outgoing packets",
1030 "number|service_name",
1031 "set port (defaults to natd/divert)",
1039 "address to use for aliasing",
1047 "address to use for incoming sessions",
1055 "take aliasing address from interface",
1062 "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
1064 "add transparent proxying / destination NAT",
1071 "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
1072 " [remote_addr[:remote_port_range]]",
1073 "redirect a port (or ports) for incoming traffic",
1080 "proto local_addr [public_addr] [remote_addr]",
1081 "redirect packets of a given proto",
1088 "local_addr[,...] public_addr",
1089 "define mapping between local and public addresses",
1097 "read options from configuration file",
1105 "enable logging of denied incoming packets",
1113 "name of syslog facility to use for logging",
1121 "punch holes in the firewall for incoming FTP/IRC DCC connections",
1126 static void ParseOption (const char* option
, const char* parms
)
1129 struct OptionInfo
* info
;
1134 const char* strValue
;
1135 struct in_addr addrValue
;
1138 CODE
* fac_record
= NULL
;
1140 * Find option from table.
1142 max
= sizeof (optionTable
) / sizeof (struct OptionInfo
);
1143 for (i
= 0, info
= optionTable
; i
< max
; i
++, info
++) {
1145 if (!strcmp (info
->name
, option
))
1148 if (info
->shortName
)
1149 if (!strcmp (info
->shortName
, option
))
1155 warnx ("unknown option %s", option
);
1166 switch (info
->parm
) {
1171 if (!strcmp (parms
, "yes"))
1174 if (!strcmp (parms
, "no"))
1177 errx (1, "%s needs yes/no parameter", option
);
1182 errx (1, "%s needs service name or "
1183 "port number parameter",
1186 uNumValue
= StrToPort (parms
, "divert");
1191 numValue
= strtol (parms
, &end
, 10);
1196 errx (1, "%s needs numeric parameter", option
);
1202 errx (1, "%s needs parameter", option
);
1207 errx (1, "%s does not take parameters", option
);
1212 errx (1, "%s needs address/host parameter", option
);
1214 StrToAddr (parms
, &addrValue
);
1218 switch (info
->type
) {
1219 case PacketAliasOption
:
1221 aliasValue
= yesNoValue
? info
->packetAliasOpt
: 0;
1222 PacketAliasSetMode (aliasValue
, info
->packetAliasOpt
);
1226 verbose
= yesNoValue
;
1230 dynamicMode
= yesNoValue
;
1234 clampMSS
= yesNoValue
;
1242 outPort
= uNumValue
;
1246 inOutPort
= uNumValue
;
1250 memcpy (&aliasAddr
, &addrValue
, sizeof (struct in_addr
));
1254 PacketAliasSetTarget(addrValue
);
1258 SetupPortRedirect (strValue
);
1262 SetupProtoRedirect(strValue
);
1265 case RedirectAddress
:
1266 SetupAddressRedirect (strValue
);
1270 PacketAliasProxyRule (strValue
);
1277 ifName
= strdup (strValue
);
1281 ReadConfigFile (strValue
);
1290 fac_record
= facilitynames
;
1291 while (fac_record
->c_name
!= NULL
) {
1293 if (!strcmp (fac_record
->c_name
, strValue
)) {
1295 logFacility
= fac_record
->c_val
;
1303 if(fac_record
->c_name
== NULL
)
1304 errx(1, "Unknown log facility name: %s", strValue
);
1309 SetupPunchFW(strValue
);
1314 void ReadConfigFile (const char* fileName
)
1322 file
= fopen (fileName
, "r");
1324 err(1, "cannot open config file %s", fileName
);
1326 while ((buf
= fgetln(file
, &len
)) != NULL
) {
1327 if (buf
[len
- 1] == '\n')
1328 buf
[len
- 1] = '\0';
1330 errx(1, "config file format error: "
1331 "last line should end with newline");
1334 * Check for comments, strip off trailing spaces.
1336 if ((ptr
= strchr(buf
, '#')))
1338 for (ptr
= buf
; isspace(*ptr
); ++ptr
)
1342 for (p
= strchr(buf
, '\0'); isspace(*--p
);)
1347 * Extract option name.
1350 while (*ptr
&& !isspace (*ptr
))
1359 * Skip white space between name and parms.
1361 while (*ptr
&& isspace (*ptr
))
1364 ParseOption (option
, *ptr
? ptr
: NULL
);
1370 static void Usage ()
1374 struct OptionInfo
* info
;
1376 fprintf (stderr
, "Recognized options:\n\n");
1378 max
= sizeof (optionTable
) / sizeof (struct OptionInfo
);
1379 for (i
= 0, info
= optionTable
; i
< max
; i
++, info
++) {
1381 fprintf (stderr
, "-%-20s %s\n", info
->name
,
1382 info
->parmDescription
);
1384 if (info
->shortName
)
1385 fprintf (stderr
, "-%-20s %s\n", info
->shortName
,
1386 info
->parmDescription
);
1388 fprintf (stderr
, " %s\n\n", info
->description
);
1394 void SetupPortRedirect (const char* parms
)
1399 struct in_addr localAddr
;
1400 struct in_addr publicAddr
;
1401 struct in_addr remoteAddr
;
1402 port_range portRange
;
1403 u_short localPort
= 0;
1404 u_short publicPort
= 0;
1405 u_short remotePort
= 0;
1406 u_short numLocalPorts
= 0;
1407 u_short numPublicPorts
= 0;
1408 u_short numRemotePorts
= 0;
1413 struct alias_link
*link
= NULL
;
1415 strcpy (buf
, parms
);
1419 protoName
= strtok (buf
, " \t");
1421 errx (1, "redirect_port: missing protocol");
1423 proto
= StrToProto (protoName
);
1425 * Extract local address.
1427 ptr
= strtok (NULL
, " \t");
1429 errx (1, "redirect_port: missing local address");
1431 separator
= strchr(ptr
, ',');
1432 if (separator
) { /* LSNAT redirection syntax. */
1433 localAddr
.s_addr
= INADDR_NONE
;
1438 if ( StrToAddrAndPortRange (ptr
, &localAddr
, protoName
, &portRange
) != 0 )
1439 errx (1, "redirect_port: invalid local port range");
1441 localPort
= GETLOPORT(portRange
);
1442 numLocalPorts
= GETNUMPORTS(portRange
);
1447 * Extract public port and optionally address.
1449 ptr
= strtok (NULL
, " \t");
1451 errx (1, "redirect_port: missing public port");
1453 separator
= strchr (ptr
, ':');
1455 if (StrToAddrAndPortRange (ptr
, &publicAddr
, protoName
, &portRange
) != 0 )
1456 errx (1, "redirect_port: invalid public port range");
1459 publicAddr
.s_addr
= INADDR_ANY
;
1460 if (StrToPortRange (ptr
, protoName
, &portRange
) != 0)
1461 errx (1, "redirect_port: invalid public port range");
1464 publicPort
= GETLOPORT(portRange
);
1465 numPublicPorts
= GETNUMPORTS(portRange
);
1468 * Extract remote address and optionally port.
1470 ptr
= strtok (NULL
, " \t");
1472 separator
= strchr (ptr
, ':');
1474 if (StrToAddrAndPortRange (ptr
, &remoteAddr
, protoName
, &portRange
) != 0)
1475 errx (1, "redirect_port: invalid remote port range");
1477 SETLOPORT(portRange
, 0);
1478 SETNUMPORTS(portRange
, 1);
1479 StrToAddr (ptr
, &remoteAddr
);
1483 SETLOPORT(portRange
, 0);
1484 SETNUMPORTS(portRange
, 1);
1485 remoteAddr
.s_addr
= INADDR_ANY
;
1488 remotePort
= GETLOPORT(portRange
);
1489 numRemotePorts
= GETNUMPORTS(portRange
);
1492 * Make sure port ranges match up, then add the redirect ports.
1494 if (numLocalPorts
!= numPublicPorts
)
1495 errx (1, "redirect_port: port ranges must be equal in size");
1497 /* Remote port range is allowed to be '0' which means all ports. */
1498 if (numRemotePorts
!= numLocalPorts
&& (numRemotePorts
!= 1 || remotePort
!= 0))
1499 errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
1501 for (i
= 0 ; i
< numPublicPorts
; ++i
) {
1502 /* If remotePort is all ports, set it to 0. */
1503 u_short remotePortCopy
= remotePort
+ i
;
1504 if (numRemotePorts
== 1 && remotePort
== 0)
1507 link
= PacketAliasRedirectPort (localAddr
,
1508 htons(localPort
+ i
),
1510 htons(remotePortCopy
),
1512 htons(publicPort
+ i
),
1517 * Setup LSNAT server pool.
1519 if (serverPool
!= NULL
&& link
!= NULL
) {
1520 ptr
= strtok(serverPool
, ",");
1521 while (ptr
!= NULL
) {
1522 if (StrToAddrAndPortRange(ptr
, &localAddr
, protoName
, &portRange
) != 0)
1523 errx(1, "redirect_port: invalid local port range");
1525 localPort
= GETLOPORT(portRange
);
1526 if (GETNUMPORTS(portRange
) != 1)
1527 errx(1, "redirect_port: local port must be single in this context");
1528 PacketAliasAddServer(link
, localAddr
, htons(localPort
));
1529 ptr
= strtok(NULL
, ",");
1535 SetupProtoRedirect(const char* parms
)
1539 struct in_addr localAddr
;
1540 struct in_addr publicAddr
;
1541 struct in_addr remoteAddr
;
1544 struct protoent
*protoent
;
1546 strcpy (buf
, parms
);
1550 protoName
= strtok(buf
, " \t");
1552 errx(1, "redirect_proto: missing protocol");
1554 protoent
= getprotobyname(protoName
);
1555 if (protoent
== NULL
)
1556 errx(1, "redirect_proto: unknown protocol %s", protoName
);
1558 proto
= protoent
->p_proto
;
1560 * Extract local address.
1562 ptr
= strtok(NULL
, " \t");
1564 errx(1, "redirect_proto: missing local address");
1566 StrToAddr(ptr
, &localAddr
);
1568 * Extract optional public address.
1570 ptr
= strtok(NULL
, " \t");
1572 StrToAddr(ptr
, &publicAddr
);
1574 publicAddr
.s_addr
= INADDR_ANY
;
1576 * Extract optional remote address.
1578 ptr
= strtok(NULL
, " \t");
1580 StrToAddr(ptr
, &remoteAddr
);
1582 remoteAddr
.s_addr
= INADDR_ANY
;
1584 * Create aliasing link.
1586 (void)PacketAliasRedirectProto(localAddr
, remoteAddr
, publicAddr
,
1590 void SetupAddressRedirect (const char* parms
)
1595 struct in_addr localAddr
;
1596 struct in_addr publicAddr
;
1598 struct alias_link
*link
;
1600 strcpy (buf
, parms
);
1602 * Extract local address.
1604 ptr
= strtok (buf
, " \t");
1606 errx (1, "redirect_address: missing local address");
1608 separator
= strchr(ptr
, ',');
1609 if (separator
) { /* LSNAT redirection syntax. */
1610 localAddr
.s_addr
= INADDR_NONE
;
1613 StrToAddr (ptr
, &localAddr
);
1617 * Extract public address.
1619 ptr
= strtok (NULL
, " \t");
1621 errx (1, "redirect_address: missing public address");
1623 StrToAddr (ptr
, &publicAddr
);
1624 link
= PacketAliasRedirectAddr(localAddr
, publicAddr
);
1627 * Setup LSNAT server pool.
1629 if (serverPool
!= NULL
&& link
!= NULL
) {
1630 ptr
= strtok(serverPool
, ",");
1631 while (ptr
!= NULL
) {
1632 StrToAddr(ptr
, &localAddr
);
1633 PacketAliasAddServer(link
, localAddr
, htons(~0));
1634 ptr
= strtok(NULL
, ",");
1639 void StrToAddr (const char* str
, struct in_addr
* addr
)
1643 if (inet_aton (str
, addr
))
1646 hp
= gethostbyname (str
);
1648 errx (1, "unknown host %s", str
);
1650 memcpy (addr
, hp
->h_addr
, sizeof (struct in_addr
));
1653 u_short
StrToPort (const char* str
, const char* proto
)
1659 port
= strtol (str
, &end
, 10);
1661 return htons (port
);
1663 sp
= getservbyname (str
, proto
);
1665 errx (1, "unknown service %s/%s", str
, proto
);
1670 int StrToPortRange (const char* str
, const char* proto
, port_range
*portRange
)
1678 /* First see if this is a service, return corresponding port if so. */
1679 sp
= getservbyname (str
,proto
);
1681 SETLOPORT(*portRange
, ntohs(sp
->s_port
));
1682 SETNUMPORTS(*portRange
, 1);
1686 /* Not a service, see if it's a single port or port range. */
1687 sep
= strchr (str
, '-');
1689 SETLOPORT(*portRange
, strtol(str
, &end
, 10));
1692 SETNUMPORTS(*portRange
, 1);
1696 /* Error in port range field. */
1697 errx (1, "unknown service %s/%s", str
, proto
);
1700 /* Port range, get the values and sanity check. */
1701 sscanf (str
, "%hu-%hu", &loPort
, &hiPort
);
1702 SETLOPORT(*portRange
, loPort
);
1703 SETNUMPORTS(*portRange
, 0); /* Error by default */
1704 if (loPort
<= hiPort
)
1705 SETNUMPORTS(*portRange
, hiPort
- loPort
+ 1);
1707 if (GETNUMPORTS(*portRange
) == 0)
1708 errx (1, "invalid port range %s", str
);
1714 int StrToProto (const char* str
)
1716 if (!strcmp (str
, "tcp"))
1719 if (!strcmp (str
, "udp"))
1722 errx (1, "unknown protocol %s. Expected tcp or udp", str
);
1725 int StrToAddrAndPortRange (const char* str
, struct in_addr
* addr
, char* proto
, port_range
*portRange
)
1729 ptr
= strchr (str
, ':');
1731 errx (1, "%s is missing port number", str
);
1736 StrToAddr (str
, addr
);
1737 return StrToPortRange (ptr
, proto
, portRange
);
1741 SetupPunchFW(const char *strValue
)
1743 unsigned int base
, num
;
1745 if (sscanf(strValue
, "%u:%u", &base
, &num
) != 2)
1746 errx(1, "punch_fw: basenumber:count parameter required");
1748 PacketAliasSetFWBase(base
, num
);
1749 (void)PacketAliasSetMode(PKT_ALIAS_PUNCH_FW
, PKT_ALIAS_PUNCH_FW
);