2 * Copyright (c) 2000-2009 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
30 * natd - Network Address Translation Daemon for FreeBSD.
32 * This software is provided free of charge, with no
33 * warranty of any kind, either expressed or implied.
34 * Use at your own risk.
36 * You may copy, modify and distribute this software (natd.c) freely.
38 * Ari Suutari <suutari@iki.fi>
41 * $FreeBSD: src/sbin/natd/natd.c,v 1.25.2.3 2000/07/11 20:00:57 ru Exp $
46 #include <sys/types.h>
47 #include <sys/socket.h>
50 #include <sys/sysctl.h>
53 #include <netinet/in.h>
54 #include <netinet/in_systm.h>
55 #include <netinet/ip.h>
56 #include <netinet/tcp.h>
57 #include <netinet/udp.h>
58 #include <netinet/ip_icmp.h>
60 #include <net/if_dl.h>
61 #include <net/route.h>
62 #include <arpa/inet.h>
78 #include <mach/mach_time.h>
79 #include <mach/clock_types.h>
84 * Default values for input and output
85 * divert socket ports.
88 #define DEFAULT_SERVICE "natd"
91 * Definition of a port range, and macros to deal with values.
92 * FORMAT: HI 16-bits == first port in range, 0 == all ports.
93 * LO 16-bits == number of ports in range
94 * NOTES: - Port values are not stored in network byte order.
97 typedef uint32_t port_range
;
99 #define GETLOPORT(x) ((x) >> 0x10)
100 #define GETNUMPORTS(x) ((x) & 0x0000ffff)
101 #define GETHIPORT(x) (GETLOPORT((x)) + GETNUMPORTS((x)))
103 /* Set y to be the low-port value in port_range variable x. */
104 #define SETLOPORT(x,y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
106 /* Set y to be the number of ports in port_range variable x. */
107 #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y))
110 * Function prototypes.
113 static void DoAliasing (int fd
, int direction
);
114 static void DaemonMode (void);
115 static void HandleRoutingInfo (int fd
);
116 static void Usage (void);
117 static char* FormatPacket (struct ip
*);
118 static void PrintPacket (struct ip
*);
119 static void SyslogPacket (struct ip
*, int priority
, const char *label
);
120 static void SetAliasAddressFromIfName (const char *ifName
);
121 static void InitiateShutdown (int);
122 static void Shutdown (int);
123 static void RefreshAddr (int);
124 static void HandleInfo (int);
125 static void ParseOption (const char* option
, const char* parms
);
126 static void ReadConfigFile (const char* fileName
);
127 static void SetupPortRedirect (const char* parms
);
128 static void SetupProtoRedirect(const char* parms
);
129 static void SetupAddressRedirect (const char* parms
);
130 static void StrToAddr (const char* str
, struct in_addr
* addr
);
131 static u_short
StrToPort (const char* str
, const char* proto
);
132 static int StrToPortRange (const char* str
, const char* proto
, port_range
*portRange
);
133 static int StrToProto (const char* str
);
134 static int StrToAddrAndPortRange (const char* str
, struct in_addr
* addr
, char* proto
, port_range
*portRange
);
135 static void ParseArgs (int argc
, char** argv
);
136 static void FlushPacketBuffer (int fd
);
137 static void DiscardIncomingPackets (int fd
);
138 static void SetupPunchFW(const char *strValue
);
145 static int background
;
147 static int assignAliasAddr
;
150 static u_short inPort
;
151 static u_short outPort
;
152 static u_short inOutPort
;
153 static struct in_addr aliasAddr
;
154 static int dynamicMode
;
157 static int aliasOverhead
;
159 static char packetBuf
[IP_MAXPACKET
];
160 static int packetLen
;
161 static struct sockaddr_in packetAddr
;
162 static int packetSock
;
163 static int packetDirection
;
164 static int dropIgnoredIncoming
;
165 static int logDropped
;
166 static int logFacility
;
174 * Note: more details on NAT-PMP can be found at :
175 * <http://files.dns-sd.org/draft-cheshire-nat-pmp.txt>
178 #define NATPMP_ANNOUNCEMENT_PORT 5350
179 #define NATPMP_PORT 5351
181 #define NATPMVERSION 0
182 #define PUBLICADDRREQ 0
185 #define MAPUDPTCPREQ 3
186 #define SERVERREPLYOP 128
189 #define NOTSUPPORTEDVERSION 1
190 #define NOTAUTHORIZED 2
191 #define NETWORKFAILURE 3
192 #define OUTOFRESOURCES 4
193 #define UNSUPPORTEDOPCODE 5
196 #define TIMER_RATE 250000
200 typedef struct stdportmaprequest
{
205 typedef struct publicportreq
{
209 uint16_t privateport
;
211 uint32_t lifetime
; /* in seconds */
214 typedef struct publicaddrreply
{
222 typedef struct publicportreply
{
227 uint16_t privateport
;
229 uint32_t lifetime
; /* in seconds */
232 typedef struct stderrreply
{
240 static int enable_natportmap
= 0;
241 static struct in_addr lastassignaliasAddr
;
242 static int portmapSock
= -1;
243 static struct in_addr
*forwardedinterfaceaddr
;
244 static char **forwardedinterfacename
;
245 static int numofinterfaces
= 0; /* has to be at least one */
246 static int numoftries
=MAXRETRY
;
247 static struct itimerval itval
;
248 static int Natdtimerset
= 0;
249 static double secdivisor
;
252 static void HandlePortMap( int fd
);
253 static void SendPortMapResponse( int fd
, struct sockaddr_in
*clientaddr
, int clientaddrlen
, unsigned char origopcode
, unsigned short result
);
254 static void SendPublicAddress( int fd
, struct sockaddr_in
*clientaddr
, int clientaddrlen
);
255 static void SendPublicPortResponse( int fd
, struct sockaddr_in
*clientaddr
, int clientaddrlen
, publicportreq
*reply
, u_short publicport
, int result
);
256 static void Doubletime( struct timeval
*tvp
);
257 static void Stoptimer();
258 static void Natdtimer();
259 static void SendPortMapMulti( );
260 static void NotifyPublicAddress();
261 static void DoPortMapping( int fd
, struct sockaddr_in
*clientaddr
, int clientaddrlen
, publicportreq
*req
);
262 static void NatPortMapPInit();
264 extern int FindAliasPortOut(struct in_addr src_addr
, struct in_addr dst_addr
, u_short src_port
, u_short pub_port
, u_char proto
, int lifetime
, char addmapping
);
266 #endif /* NATPORTMAP */
268 int main (int argc
, char** argv
)
274 struct sockaddr_in addr
;
280 * Initialize packet aliasing software.
281 * Done already here to be able to alter option bits
282 * during command line and configuration file processing.
297 aliasAddr
.s_addr
= INADDR_NONE
;
299 lastassignaliasAddr
.s_addr
= INADDR_NONE
;
304 logFacility
= LOG_DAEMON
;
306 * Mark packet buffer empty.
309 packetDirection
= DONT_KNOW
;
311 ParseArgs (argc
, argv
);
313 * Open syslog channel.
315 openlog ("natd", LOG_CONS
| LOG_PID
| (verbose
? LOG_PERROR
: 0),
318 * Check that valid aliasing address has been given.
320 if (aliasAddr
.s_addr
== INADDR_NONE
&& ifName
== NULL
)
321 errx (1, "aliasing address not given");
324 * Check that valid port number is known.
326 if (inPort
!= 0 || outPort
!= 0)
327 if (inPort
== 0 || outPort
== 0)
328 errx (1, "both input and output ports are required");
330 if (inPort
== 0 && outPort
== 0 && inOutPort
== 0)
331 ParseOption ("port", DEFAULT_SERVICE
);
334 * Check if ignored packets should be dropped.
336 dropIgnoredIncoming
= PacketAliasSetMode (0, 0);
337 dropIgnoredIncoming
&= PKT_ALIAS_DENY_INCOMING
;
339 * Create divert sockets. Use only one socket if -p was specified
340 * on command line. Otherwise, create separate sockets for
341 * outgoing and incoming connnections.
345 divertInOut
= socket (PF_INET
, SOCK_RAW
, IPPROTO_DIVERT
);
346 if (divertInOut
== -1)
347 Quit ("Unable to create divert socket.");
355 addr
.sin_family
= AF_INET
;
356 addr
.sin_addr
.s_addr
= INADDR_ANY
;
357 addr
.sin_port
= inOutPort
;
359 if (bind (divertInOut
,
360 (struct sockaddr
*) &addr
,
362 Quit ("Unable to bind divert socket.");
366 divertIn
= socket (PF_INET
, SOCK_RAW
, IPPROTO_DIVERT
);
368 Quit ("Unable to create incoming divert socket.");
370 divertOut
= socket (PF_INET
, SOCK_RAW
, IPPROTO_DIVERT
);
372 Quit ("Unable to create outgoing divert socket.");
377 * Bind divert sockets.
380 addr
.sin_family
= AF_INET
;
381 addr
.sin_addr
.s_addr
= INADDR_ANY
;
382 addr
.sin_port
= inPort
;
385 (struct sockaddr
*) &addr
,
387 Quit ("Unable to bind incoming divert socket.");
389 addr
.sin_family
= AF_INET
;
390 addr
.sin_addr
.s_addr
= INADDR_ANY
;
391 addr
.sin_port
= outPort
;
394 (struct sockaddr
*) &addr
,
396 Quit ("Unable to bind outgoing divert socket.");
399 * Create routing socket if interface name specified and in dynamic mode.
405 routeSock
= socket (PF_ROUTE
, SOCK_RAW
, 0);
407 Quit ("Unable to create routing info socket.");
412 SetAliasAddressFromIfName (ifName
);
416 * Create socket for sending ICMP messages.
418 icmpSock
= socket (AF_INET
, SOCK_RAW
, IPPROTO_ICMP
);
420 Quit ("Unable to create ICMP socket.");
422 if ((fdFlags
= fcntl(icmpSock
, F_GETFL
, 0)) == -1)
423 Quit ("fcntl F_GETFL ICMP socket.");
424 fdFlags
|= O_NONBLOCK
;
425 if (fcntl(icmpSock
, F_SETFL
, fdFlags
) == -1)
426 Quit ("fcntl F_SETFL ICMP socket.");
429 if ( enable_natportmap
)
431 /* create socket to listen for port mapping */
432 portmapSock
= socket( AF_INET
, SOCK_DGRAM
, 0);
433 if ( portmapSock
!= -1 )
435 addr
.sin_family
= AF_INET
;
436 addr
.sin_addr
.s_addr
= INADDR_ANY
;
437 addr
.sin_port
= htons(NATPMP_PORT
);
439 if (bind ( portmapSock
,
440 (struct sockaddr
*) &addr
,
442 printf("Binding to NATPM port failed!\n");
444 /* NATPORTMAPP initial set up */
447 if ( !Natdtimerset
){
449 signal(SIGALRM
, Natdtimer
);
452 #endif /* NATPORTMAP */
455 * Become a daemon unless verbose mode was requested.
460 * Catch signals to manage shutdown and
461 * refresh of interface address.
463 siginterrupt(SIGTERM
, 1);
464 siginterrupt(SIGHUP
, 1);
465 signal (SIGTERM
, InitiateShutdown
);
466 signal (SIGHUP
, RefreshAddr
);
467 signal (SIGINFO
, HandleInfo
);
469 * Set alias address if it has been given.
471 if (aliasAddr
.s_addr
!= INADDR_NONE
)
473 PacketAliasSetAddress (aliasAddr
);
475 if ( (enable_natportmap
) && (aliasAddr
.s_addr
!= lastassignaliasAddr
.s_addr
) ){
476 lastassignaliasAddr
.s_addr
= aliasAddr
.s_addr
;
477 NotifyPublicAddress();
482 * We need largest descriptor number for select.
487 if (divertIn
> fdMax
)
490 if (divertOut
> fdMax
)
493 if (divertInOut
> fdMax
)
496 if (routeSock
> fdMax
)
499 if (icmpSock
> fdMax
)
503 if ( portmapSock
> fdMax
)
510 if (divertInOut
!= -1 && !ifName
&& packetSock
== -1) {
512 * When using only one socket, just call
513 * DoAliasing repeatedly to process packets.
515 DoAliasing (divertInOut
, DONT_KNOW
);
519 * Build read mask from socket descriptors to select.
522 FD_ZERO (&writeMask
);
525 * If there is unsent packet in buffer, use select
526 * to check when socket comes writable again.
528 if (packetSock
!= -1) {
530 FD_SET (packetSock
, &writeMask
);
534 * No unsent packet exists - safe to check if
535 * new ones are available.
538 FD_SET (divertIn
, &readMask
);
541 FD_SET (divertOut
, &readMask
);
543 if (divertInOut
!= -1)
544 FD_SET (divertInOut
, &readMask
);
547 FD_SET(icmpSock
, &readMask
);
550 * Routing info is processed always.
553 FD_SET (routeSock
, &readMask
);
555 if ( portmapSock
!= -1 )
556 FD_SET (portmapSock
, &readMask
);
558 if (select (fdMax
+ 1,
564 if (errno
== EINTR
) {
571 Quit ("Select failed.");
574 if (packetSock
!= -1)
575 if (FD_ISSET (packetSock
, &writeMask
))
576 FlushPacketBuffer (packetSock
);
579 if (FD_ISSET (divertIn
, &readMask
))
580 DoAliasing (divertIn
, INPUT
);
583 if (FD_ISSET (divertOut
, &readMask
))
584 DoAliasing (divertOut
, OUTPUT
);
586 if (divertInOut
!= -1)
587 if (FD_ISSET (divertInOut
, &readMask
))
588 DoAliasing (divertInOut
, DONT_KNOW
);
591 if (FD_ISSET (routeSock
, &readMask
))
592 HandleRoutingInfo (routeSock
);
595 if (FD_ISSET (icmpSock
, &readMask
))
596 DiscardIncomingPackets (icmpSock
);
599 if ( portmapSock
!= -1)
600 if (FD_ISSET (portmapSock
, &readMask
))
601 HandlePortMap( portmapSock
);
611 static void DaemonMode ()
618 pidFile
= fopen (PIDFILE
, "w");
621 fprintf (pidFile
, "%d\n", getpid ());
630 fd
= open("/var/run/natd.log", O_WRONLY
|O_CREAT
|O_TRUNC
, 0644);
632 if (fd
!= STDOUT_FILENO
) {
633 dup2(fd
, STDOUT_FILENO
);
636 dup2(STDOUT_FILENO
, STDERR_FILENO
);
642 static void ParseArgs (int argc
, char** argv
)
647 int len
; /* bounds checking */
649 for (arg
= 1; arg
< argc
; arg
++) {
654 warnx ("invalid option %s", opt
);
661 while (arg
< argc
- 1) {
663 if (argv
[arg
+ 1][0] == '-')
667 strncat (parmBuf
, " ", sizeof(parmBuf
) - (len
+ 1));
668 len
+= strlen(parmBuf
+ len
);
672 strncat (parmBuf
, argv
[arg
], sizeof(parmBuf
) - (len
+ 1));
673 len
+= strlen(parmBuf
+ len
);
677 ParseOption (opt
+ 1, (len
? parmBuf
: NULL
));
682 static void DoAliasing (int fd
, int direction
)
690 if (assignAliasAddr
) {
692 SetAliasAddressFromIfName (ifName
);
696 * Get packet from socket.
698 addrSize
= sizeof packetAddr
;
699 origBytes
= recvfrom (fd
,
703 (struct sockaddr
*) &packetAddr
,
706 if (origBytes
== -1) {
709 Warn ("read from divert socket failed");
714 * This is a IP packet.
716 ip
= (struct ip
*) packetBuf
;
717 if (direction
== DONT_KNOW
) {
718 if (packetAddr
.sin_addr
.s_addr
== INADDR_ANY
)
726 * Print packet direction and protocol type.
728 printf (direction
== OUTPUT
? "Out " : "In ");
744 printf ("[%d] ", ip
->ip_p
);
753 if (direction
== OUTPUT
) {
755 * Outgoing packets. Do aliasing.
757 PacketAliasOut (packetBuf
, IP_MAXPACKET
);
764 status
= PacketAliasIn (packetBuf
, IP_MAXPACKET
);
765 if (status
== PKT_ALIAS_IGNORED
&&
766 dropIgnoredIncoming
) {
769 printf (" dropped.\n");
772 SyslogPacket (ip
, LOG_WARNING
, "denied");
778 * Length might have changed during aliasing.
780 bytes
= ntohs (ip
->ip_len
);
782 * Update alias overhead size for outgoing packets.
784 if (direction
== OUTPUT
&&
785 bytes
- origBytes
> aliasOverhead
)
786 aliasOverhead
= bytes
- origBytes
;
791 * Print addresses after aliasing.
793 printf (" aliased to\n");
801 packetDirection
= direction
;
803 FlushPacketBuffer (fd
);
806 static void FlushPacketBuffer (int fd
)
811 * Put packet back for processing.
817 (struct sockaddr
*) &packetAddr
,
820 if (wrote
!= packetLen
) {
822 * If buffer space is not available,
823 * just return. Main loop will take care of
824 * retrying send when space becomes available.
826 if (errno
== ENOBUFS
)
829 if (errno
== EMSGSIZE
) {
831 if (packetDirection
== OUTPUT
&&
833 SendNeedFragIcmp (icmpSock
,
834 (struct ip
*) packetBuf
,
835 ifMTU
- aliasOverhead
);
839 snprintf (msgBuf
, sizeof(msgBuf
), "failed to write packet back");
847 static void HandleRoutingInfo (int fd
)
850 struct if_msghdr ifMsg
;
852 * Get packet from socket.
854 bytes
= read (fd
, &ifMsg
, sizeof ifMsg
);
857 Warn ("read from routing socket failed");
861 if (ifMsg
.ifm_version
!= RTM_VERSION
) {
863 Warn ("unexpected packet read from routing socket");
868 printf ("Routing message %#x received.\n", ifMsg
.ifm_type
);
870 if ((ifMsg
.ifm_type
== RTM_NEWADDR
|| ifMsg
.ifm_type
== RTM_IFINFO
) &&
871 ifMsg
.ifm_index
== ifIndex
) {
873 printf("Interface address/MTU has probably changed.\n");
878 static void DiscardIncomingPackets (int fd
)
880 struct sockaddr_in sin
;
882 socklen_t slen
= sizeof(sin
);
884 while (recvfrom(fd
, buffer
, sizeof(buffer
), 0, (struct sockaddr
*)&sin
, &slen
) != -1) {
893 struct mach_timebase_info info
;
895 (void) mach_timebase_info (&info
);
897 secdivisor
= ( (double)info
.denom
/ (double)info
.numer
) * 1000;
906 now
= mach_absolute_time();
907 epochtime
= (now
/ secdivisor
) / USEC_PER_SEC
;
908 return ( epochtime
);
912 /* set up neccessary info for doing NatPortMapP */
913 static void NatPortMapPInit()
916 struct ifaddrs
*ifap
, *ifa
;
918 forwardedinterfaceaddr
= (struct in_addr
*)
919 malloc(numofinterfaces
* sizeof(*forwardedinterfaceaddr
));
920 bzero(forwardedinterfaceaddr
,
921 numofinterfaces
* sizeof(*forwardedinterfaceaddr
));
922 /* interface address hasn't been set up, get interface address */
924 if (getifaddrs(&ifap
) == -1)
925 Quit ("getifaddrs failed.");
927 for ( ifa
= ifap
; ifa
; ifa
=ifa
->ifa_next
)
929 struct sockaddr_in
* a
;
930 if (ifa
->ifa_addr
->sa_family
!= AF_INET
)
934 a
= (struct sockaddr_in
*)ifa
->ifa_addr
;
935 for ( i
= 0; i
< numofinterfaces
; i
++ )
937 if (strcmp(ifa
->ifa_name
, forwardedinterfacename
[i
]))
941 if (forwardedinterfaceaddr
[i
].s_addr
== 0)
943 /* copy the first IP address */
944 forwardedinterfaceaddr
[i
] = a
->sin_addr
;
953 /* SendPortMapResponse */
954 /* send generic reponses to NATPORTMAP requests */
955 static void SendPortMapResponse( int fd
, struct sockaddr_in
*clientaddr
, int clientaddrlen
, unsigned char origopcode
, unsigned short result
)
960 reply
.version
= NATPMVERSION
;
961 reply
.opcode
= origopcode
+ SERVERREPLYOP
;
962 reply
.result
= htons(result
);
963 reply
.epoch
= htonl(getuptime());
964 bytes
= sendto( fd
, (void*)&reply
, sizeof(reply
), 0, (struct sockaddr
*)clientaddr
, clientaddrlen
);
965 if ( bytes
!= sizeof(reply
) )
966 printf( "PORTMAP::problem sending portmap reply - opcode %d\n", reply
.opcode
);
969 /* SendPublicAddress */
970 /* return public address to requestor */
971 static void SendPublicAddress( int fd
, struct sockaddr_in
*clientaddr
, int clientaddrlen
)
974 publicaddrreply reply
;
977 reply
.version
= NATPMVERSION
;
978 reply
.opcode
= SERVERREPLYOP
+ PUBLICADDRREQ
;
979 reply
.result
= SUCCESS
;
980 reply
.addr
= lastassignaliasAddr
;
981 reply
.epoch
= htonl(getuptime());
983 bytes
= sendto (fd
, (void*)&reply
, sizeof(reply
), 0, (struct sockaddr
*)clientaddr
, clientaddrlen
);
984 if ( bytes
!= sizeof(reply
) )
985 printf( "PORTMAP::problem sending portmap reply - opcode %d\n", reply
.opcode
);
988 /* SendPublicPortResponse */
989 /* response for portmap request and portmap removal request */
990 /* publicport <= 0 means error */
991 static void SendPublicPortResponse( int fd
, struct sockaddr_in
*clientaddr
, int clientaddrlen
, publicportreq
*req
, u_short publicport
, int result
)
995 publicportreply reply
;
997 bzero(&reply
, sizeof(publicportreply
));
998 reply
.version
= NATPMVERSION
;
999 reply
.opcode
= SERVERREPLYOP
+ req
->opcode
;
1001 /* error in port mapping */
1002 reply
.result
= htons(OUTOFRESOURCES
);
1004 reply
.result
= SUCCESS
;
1006 reply
.epoch
= htonl(getuptime());
1008 reply
.privateport
= req
->privateport
;
1010 /* adding or renewing a mapping */
1011 if ( req
->lifetime
) {
1012 reply
.publicport
= publicport
;
1013 reply
.lifetime
= req
->lifetime
;
1015 bytes
= sendto (fd
, (void*)&reply
, sizeof(publicportreply
), 0, (struct sockaddr
*)clientaddr
, clientaddrlen
);
1016 if ( bytes
!= sizeof(publicportreply
) )
1017 printf( "PORTMAP::problem sending portmap reply - opcode %d\n", req
->opcode
);
1020 /* SendPortMapMulti */
1021 /* send multicast to local network for new alias address */
1022 static void SendPortMapMulti()
1025 publicaddrreply reply
;
1027 struct sockaddr_in multiaddr
;
1031 #define LOCALGROUP "224.0.0.1"
1033 memset(&multiaddr
,0,sizeof(struct sockaddr_in
));
1034 multiaddr
.sin_family
=AF_INET
;
1035 multiaddr
.sin_addr
.s_addr
=inet_addr(LOCALGROUP
);
1036 multiaddr
.sin_port
=htons(NATPMP_ANNOUNCEMENT_PORT
);
1037 reply
.version
= NATPMVERSION
;
1038 reply
.opcode
= SERVERREPLYOP
+ PUBLICADDRREQ
;
1039 reply
.result
= SUCCESS
;
1040 reply
.addr
= lastassignaliasAddr
;
1043 /* send multicast to all forwarded interfaces */
1044 for ( i
= 0; i
< numofinterfaces
; i
++)
1046 if (forwardedinterfaceaddr
[i
].s_addr
== 0)
1050 multisock
= socket( AF_INET
, SOCK_DGRAM
, 0);
1052 if ( multisock
== -1 )
1054 printf("cannot get socket for sending multicast\n");
1057 if (setsockopt(multisock
, IPPROTO_IP
, IP_MULTICAST_IF
, &forwardedinterfaceaddr
[i
], sizeof(struct in_addr
)) < 0)
1059 printf("setsockopt failed\n");
1063 bytes
= sendto (multisock
, (void*)&reply
, sizeof(reply
), 0, (struct sockaddr
*)&multiaddr
, sizeof(multiaddr
));
1064 if ( bytes
!= sizeof(reply
) )
1065 printf( "PORTMAP::problem sending multicast alias address - opcode %d\n", reply
.opcode
);
1071 /* double the time value */
1072 static void Doubletime( struct timeval
*tvp
)
1075 timeradd(tvp
, tvp
, tvp
);
1079 /* stop running natd timer */
1080 static void Stoptimer()
1082 itval
.it_value
.tv_sec
= 0;
1083 itval
.it_value
.tv_usec
= 0;
1084 if (setitimer(ITIMER_REAL
, &itval
, (struct itimerval
*)NULL
) < 0)
1085 printf( "setitimer err: %d\n", errno
);
1089 /* timer routine to send new public IP address */
1090 static void Natdtimer()
1092 if ( !enable_natportmap
)
1097 if ( numoftries
< MAXRETRY
){
1098 Doubletime( &itval
.it_value
);
1099 itval
.it_interval
.tv_sec
= 0;
1100 itval
.it_interval
.tv_usec
= 0;
1101 if (setitimer(ITIMER_REAL
, &itval
, (struct itimerval
*)NULL
) < 0)
1102 printf( "setitimer err: %d\n", errno
);
1112 /* NotifyPublicAddress */
1113 /* Advertise new public address */
1114 static void NotifyPublicAddress()
1116 if ( numoftries
< MAXRETRY
)
1118 /* there is an old timer running, cancel it */
1121 /* send up new timer */
1124 itval
.it_value
.tv_sec
= 0;
1125 itval
.it_value
.tv_usec
= TIMER_RATE
;
1126 itval
.it_interval
.tv_sec
= 0;
1127 itval
.it_interval
.tv_usec
= 0;
1128 if (setitimer(ITIMER_REAL
, &itval
, (struct itimerval
*)NULL
) < 0)
1129 printf( "setitimer err: %d\n", errno
);
1134 /* find/add/remove port mapping from alias manager */
1135 void DoPortMapping( int fd
, struct sockaddr_in
*clientaddr
, int clientaddrlen
, publicportreq
*req
)
1137 u_char proto
= IPPROTO_TCP
;
1139 struct in_addr inany
= { INADDR_ANY
};
1141 if ( req
->opcode
== MAPUDPREQ
)
1142 proto
= IPPROTO_UDP
;
1143 if ( req
->lifetime
== 0)
1145 /* remove port mapping */
1146 if ( !FindAliasPortOut( clientaddr
->sin_addr
,
1151 ntohl(req
->lifetime
),
1153 /* FindAliasPortOut returns no error, port successfully removed, return no error response to client */
1154 SendPublicPortResponse( fd
, clientaddr
, clientaddrlen
, req
, 0, 0 );
1156 /* deleting port fails, return error */
1157 SendPublicPortResponse( fd
, clientaddr
, clientaddrlen
, req
, 0, -1 );
1161 /* look for port mapping - public port is ignored in this case */
1162 /* create port mapping - map provided public port to private port if public port is not 0 */
1163 aliasport
= FindAliasPortOut( clientaddr
->sin_addr
,
1164 inany
, /* lastassignaliasAddr */
1168 ntohl(req
->lifetime
),
1170 /* aliasport should be non zero if mapping is successfully, else -1 is returned, alias port shouldn't be zero???? */
1171 SendPublicPortResponse( fd
, clientaddr
, clientaddrlen
, req
, aliasport
, 0 );
1177 /* handle all packets sent to NATPORTMAP port */
1178 static void HandlePortMap( int fd
)
1180 #define MAXBUFFERSIZE 100
1182 struct sockaddr_in clientaddr
;
1183 socklen_t clientaddrlen
;
1184 unsigned char buffer
[MAXBUFFERSIZE
];
1186 unsigned short result
= SUCCESS
;
1187 struct stdportmaprequest
*req
;
1189 clientaddrlen
= sizeof( clientaddr
);
1190 bytes
= recvfrom( fd
, buffer
, sizeof(buffer
), 0, (struct sockaddr
*)&clientaddr
, &clientaddrlen
);
1193 printf( "Read NATPM port error\n");
1196 else if ( bytes
< sizeof(stdportmaprequest
) )
1198 /* drop any requests that are too short */
1202 req
= (struct stdportmaprequest
*)buffer
;
1208 printf("HandlePortMap from %s:%u length= %d: ", inet_ntoa(clientaddr
.sin_addr
), clientaddr
.sin_port
, bytes
);
1209 for ( i
= 0; i
<bytes
; i
++)
1211 printf("%02x", buffer
[i
]);
1217 /* drop any reply packets that we receive on the floor */
1218 if ( req
->opcode
>= SERVERREPLYOP
)
1223 /* check client version */
1224 if ( req
->version
> NATPMVERSION
)
1225 result
= NOTSUPPORTEDVERSION
;
1226 else if ( !enable_natportmap
)
1227 /* natd wasn't launched with portmapping enabled */
1228 result
= NOTAUTHORIZED
;
1232 SendPortMapResponse( fd
, &clientaddr
, clientaddrlen
, req
->opcode
, result
);
1236 switch ( req
->opcode
)
1240 if ( bytes
== sizeof(stdportmaprequest
) )
1241 SendPublicAddress(fd
, &clientaddr
, clientaddrlen
);
1249 if ( bytes
== sizeof(publicportreq
) )
1250 DoPortMapping( fd
, &clientaddr
, clientaddrlen
, (publicportreq
*)req
);
1256 SendPortMapResponse( fd
, &clientaddr
, clientaddrlen
, req
->opcode
, UNSUPPORTEDOPCODE
);
1261 #endif /* NATPORTMAP */
1263 static void PrintPacket (struct ip
* ip
)
1265 printf ("%s", FormatPacket (ip
));
1268 static void SyslogPacket (struct ip
* ip
, int priority
, const char *label
)
1270 syslog (priority
, "%s %s", label
, FormatPacket (ip
));
1273 static char* FormatPacket (struct ip
* ip
)
1275 static char buf
[256];
1276 struct tcphdr
* tcphdr
;
1277 struct udphdr
* udphdr
;
1278 struct icmp
* icmphdr
;
1282 strlcpy (src
, inet_ntoa (ip
->ip_src
), sizeof(src
));
1283 strlcpy (dst
, inet_ntoa (ip
->ip_dst
), sizeof(dst
));
1287 tcphdr
= (struct tcphdr
*) ((char*) ip
+ (ip
->ip_hl
<< 2));
1288 snprintf (buf
, sizeof(buf
), "[TCP] %s:%d -> %s:%d",
1290 ntohs (tcphdr
->th_sport
),
1292 ntohs (tcphdr
->th_dport
));
1296 udphdr
= (struct udphdr
*) ((char*) ip
+ (ip
->ip_hl
<< 2));
1297 snprintf (buf
, sizeof(buf
), "[UDP] %s:%d -> %s:%d",
1299 ntohs (udphdr
->uh_sport
),
1301 ntohs (udphdr
->uh_dport
));
1305 icmphdr
= (struct icmp
*) ((char*) ip
+ (ip
->ip_hl
<< 2));
1306 snprintf (buf
, sizeof(buf
), "[ICMP] %s -> %s %u(%u)",
1310 icmphdr
->icmp_code
);
1314 snprintf (buf
, sizeof(buf
), "[%d] %s -> %s ", ip
->ip_p
, src
, dst
);
1322 SetAliasAddressFromIfName(const char *ifn
)
1326 char *buf
, *lim
, *next
;
1327 struct if_msghdr
*ifm
;
1328 struct ifa_msghdr
*ifam
;
1329 struct sockaddr_dl
*sdl
;
1330 struct sockaddr_in
*sin
;
1335 mib
[3] = AF_INET
; /* Only IP addresses please */
1336 mib
[4] = NET_RT_IFLIST
;
1337 mib
[5] = 0; /* ifIndex??? */
1339 * Get interface data.
1341 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) == -1)
1342 err(1, "iflist-sysctl-estimate");
1343 if ((buf
= malloc(needed
)) == NULL
)
1344 errx(1, "malloc failed");
1345 if (sysctl(mib
, 6, buf
, &needed
, NULL
, 0) == -1)
1346 err(1, "iflist-sysctl-get");
1349 * Loop through interfaces until one with
1350 * given name is found. This is done to
1351 * find correct interface index for routing
1352 * message processing.
1356 while (next
< lim
) {
1357 ifm
= (struct if_msghdr
*)next
;
1358 next
+= ifm
->ifm_msglen
;
1359 if (ifm
->ifm_version
!= RTM_VERSION
) {
1361 warnx("routing message version %d "
1362 "not understood", ifm
->ifm_version
);
1365 if (ifm
->ifm_type
== RTM_IFINFO
) {
1366 sdl
= (struct sockaddr_dl
*)(ifm
+ 1);
1367 if (strlen(ifn
) == sdl
->sdl_nlen
&&
1368 strncmp(ifn
, sdl
->sdl_data
, sdl
->sdl_nlen
) == 0) {
1369 ifIndex
= ifm
->ifm_index
;
1370 ifMTU
= ifm
->ifm_data
.ifi_mtu
;
1372 PacketAliasClampMSS(ifMTU
- sizeof(struct tcphdr
) - sizeof(struct ip
));
1378 errx(1, "unknown interface name %s", ifn
);
1380 * Get interface address.
1382 if (aliasAddr
.s_addr
== INADDR_NONE
) {
1384 while (next
< lim
) {
1385 ifam
= (struct ifa_msghdr
*)next
;
1386 next
+= ifam
->ifam_msglen
;
1387 if (ifam
->ifam_version
!= RTM_VERSION
) {
1389 warnx("routing message version %d "
1390 "not understood", ifam
->ifam_version
);
1393 if (ifam
->ifam_type
!= RTM_NEWADDR
)
1395 if (ifam
->ifam_addrs
& RTA_IFA
) {
1397 char *cp
= (char *)(ifam
+ 1);
1399 #define ROUNDUP(a) \
1400 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t))
1401 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
1403 for (i
= 1; i
< RTA_IFA
; i
<<= 1)
1404 if (ifam
->ifam_addrs
& i
)
1405 ADVANCE(cp
, (struct sockaddr
*)cp
);
1406 if (((struct sockaddr
*)cp
)->sa_family
== AF_INET
) {
1407 sin
= (struct sockaddr_in
*)cp
;
1413 errx(1, "%s: cannot get interface address", ifn
);
1415 PacketAliasSetAddress(sin
->sin_addr
);
1417 if ( (enable_natportmap
) && (sin
->sin_addr
.s_addr
!= lastassignaliasAddr
.s_addr
) )
1419 lastassignaliasAddr
.s_addr
= sin
->sin_addr
.s_addr
;
1420 /* make sure the timer handler was set before setting timer */
1421 if ( !Natdtimerset
){
1423 signal(SIGALRM
, Natdtimer
);
1425 NotifyPublicAddress();
1428 syslog(LOG_INFO
, "Aliasing to %s, mtu %d bytes",
1429 inet_ntoa(sin
->sin_addr
), ifMTU
);
1435 void Quit (const char* msg
)
1441 void Warn (const char* msg
)
1444 syslog (LOG_ALERT
, "%s (%m)", msg
);
1449 static void RefreshAddr (int sig
)
1452 assignAliasAddr
= 1;
1455 static void InitiateShutdown (int sig
)
1458 * Start timer to allow kernel gracefully
1459 * shutdown existing connections when system
1462 siginterrupt(SIGALRM
, 1);
1463 signal (SIGALRM
, Shutdown
);
1467 static void Shutdown (int sig
)
1472 static void HandleInfo (int sig
)
1478 * Different options recognized by this program.
1518 * Option information structure (used by ParseOption).
1526 const char* parmDescription
;
1527 const char* description
;
1529 const char* shortName
;
1533 * Table of known options.
1536 static struct OptionInfo optionTable
[] = {
1538 { PacketAliasOption
,
1539 PKT_ALIAS_UNREGISTERED_ONLY
,
1542 "alias only unregistered addresses",
1543 "unregistered_only",
1546 { PacketAliasOption
,
1554 { PacketAliasOption
,
1555 PKT_ALIAS_PROXY_ONLY
,
1562 { PacketAliasOption
,
1566 "operate in reverse mode",
1570 { PacketAliasOption
,
1571 PKT_ALIAS_DENY_INCOMING
,
1574 "allow incoming connections",
1578 { PacketAliasOption
,
1579 PKT_ALIAS_USE_SOCKETS
,
1582 "use sockets to inhibit port conflict",
1586 { PacketAliasOption
,
1587 PKT_ALIAS_SAME_PORTS
,
1590 "try to keep original port numbers for connections",
1598 "verbose mode, dump packet information",
1606 "dynamic mode, automatically detect interface address changes",
1614 "enable TCP MSS clamping",
1621 "number|service_name",
1622 "set port for incoming packets",
1629 "number|service_name",
1630 "set port for outgoing packets",
1637 "number|service_name",
1638 "set port (defaults to natd/divert)",
1646 "address to use for aliasing",
1654 "address to use for incoming sessions",
1662 "take aliasing address from interface",
1669 "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
1671 "add transparent proxying / destination NAT",
1678 "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
1679 " [remote_addr[:remote_port_range]]",
1680 "redirect a port (or ports) for incoming traffic",
1687 "proto local_addr [public_addr] [remote_addr]",
1688 "redirect packets of a given proto",
1695 "local_addr[,...] public_addr",
1696 "define mapping between local and public addresses",
1704 "read options from configuration file",
1712 "enable logging of denied incoming packets",
1720 "name of syslog facility to use for logging",
1728 "punch holes in the firewall for incoming FTP/IRC DCC connections",
1737 "enable NATPortMap protocol",
1738 "enable_natportmap",
1745 "take aliasing address to interface",
1746 "natportmap_interface",
1752 static void ParseOption (const char* option
, const char* parms
)
1755 struct OptionInfo
* info
;
1760 const char* strValue
;
1761 struct in_addr addrValue
;
1764 CODE
* fac_record
= NULL
;
1766 * Find option from table.
1768 max
= sizeof (optionTable
) / sizeof (struct OptionInfo
);
1769 for (i
= 0, info
= optionTable
; i
< max
; i
++, info
++) {
1771 if (!strcmp (info
->name
, option
))
1774 if (info
->shortName
)
1775 if (!strcmp (info
->shortName
, option
))
1781 warnx ("unknown option %s", option
);
1792 switch (info
->parm
) {
1797 if (!strcmp (parms
, "yes"))
1800 if (!strcmp (parms
, "no"))
1803 errx (1, "%s needs yes/no parameter", option
);
1808 errx (1, "%s needs service name or "
1809 "port number parameter",
1812 uNumValue
= StrToPort (parms
, "divert");
1817 numValue
= strtol (parms
, &end
, 10);
1822 errx (1, "%s needs numeric parameter", option
);
1828 errx (1, "%s needs parameter", option
);
1833 errx (1, "%s does not take parameters", option
);
1838 errx (1, "%s needs address/host parameter", option
);
1840 StrToAddr (parms
, &addrValue
);
1844 switch (info
->type
) {
1845 case PacketAliasOption
:
1847 aliasValue
= yesNoValue
? info
->packetAliasOpt
: 0;
1848 PacketAliasSetMode (aliasValue
, info
->packetAliasOpt
);
1852 verbose
= yesNoValue
;
1856 dynamicMode
= yesNoValue
;
1860 clampMSS
= yesNoValue
;
1868 outPort
= uNumValue
;
1872 inOutPort
= uNumValue
;
1876 memcpy (&aliasAddr
, &addrValue
, sizeof (struct in_addr
));
1880 PacketAliasSetTarget(addrValue
);
1884 SetupPortRedirect (strValue
);
1888 SetupProtoRedirect(strValue
);
1891 case RedirectAddress
:
1892 SetupAddressRedirect (strValue
);
1896 PacketAliasProxyRule (strValue
);
1903 ifName
= strdup (strValue
);
1907 ReadConfigFile (strValue
);
1916 fac_record
= facilitynames
;
1917 while (fac_record
->c_name
!= NULL
) {
1919 if (!strcmp (fac_record
->c_name
, strValue
)) {
1921 logFacility
= fac_record
->c_val
;
1929 if(fac_record
->c_name
== NULL
)
1930 errx(1, "Unknown log facility name: %s", strValue
);
1935 SetupPunchFW(strValue
);
1940 enable_natportmap
= yesNoValue
;
1944 case ToInterfaceName
:
1946 if (forwardedinterfacename
!= NULL
)
1948 if ( (forwardedinterfacename
= realloc( forwardedinterfacename
, (numofinterfaces
+1) * sizeof(*forwardedinterfacename
))) == NULL
){
1949 printf("realloc error, cannot allocate memory for fowarded interface name.\n");
1954 if ( (forwardedinterfacename
= malloc( sizeof(*forwardedinterfacename
) )) == NULL
){
1955 printf("malloc error, cannot allocate memory for fowarded interface name.\n");
1960 forwardedinterfacename
[numofinterfaces
] = strdup(strValue
);
1971 void ReadConfigFile (const char* fileName
)
1979 file
= fopen (fileName
, "r");
1981 err(1, "cannot open config file %s", fileName
);
1983 while ((buf
= fgetln(file
, &len
)) != NULL
) {
1984 if (buf
[len
- 1] == '\n')
1985 buf
[len
- 1] = '\0';
1987 errx(1, "config file format error: "
1988 "last line should end with newline");
1991 * Check for comments, strip off trailing spaces.
1993 if ((ptr
= strchr(buf
, '#')))
1995 for (ptr
= buf
; isspace(*ptr
); ++ptr
)
1999 for (p
= strchr(buf
, '\0'); isspace(*--p
);)
2004 * Extract option name.
2007 while (*ptr
&& !isspace (*ptr
))
2016 * Skip white space between name and parms.
2018 while (*ptr
&& isspace (*ptr
))
2021 ParseOption (option
, *ptr
? ptr
: NULL
);
2027 static void Usage ()
2031 struct OptionInfo
* info
;
2033 fprintf (stderr
, "Recognized options:\n\n");
2035 max
= sizeof (optionTable
) / sizeof (struct OptionInfo
);
2036 for (i
= 0, info
= optionTable
; i
< max
; i
++, info
++) {
2038 fprintf (stderr
, "-%-20s %s\n", info
->name
,
2039 info
->parmDescription
);
2041 if (info
->shortName
)
2042 fprintf (stderr
, "-%-20s %s\n", info
->shortName
,
2043 info
->parmDescription
);
2045 fprintf (stderr
, " %s\n\n", info
->description
);
2051 void SetupPortRedirect (const char* parms
)
2056 struct in_addr localAddr
;
2057 struct in_addr publicAddr
;
2058 struct in_addr remoteAddr
;
2059 port_range portRange
;
2060 u_short localPort
= 0;
2061 u_short publicPort
= 0;
2062 u_short remotePort
= 0;
2063 u_short numLocalPorts
= 0;
2064 u_short numPublicPorts
= 0;
2065 u_short numRemotePorts
= 0;
2070 struct alias_link
*link
= NULL
;
2072 strlcpy (buf
, parms
, sizeof(buf
));
2076 protoName
= strtok (buf
, " \t");
2078 errx (1, "redirect_port: missing protocol");
2080 proto
= StrToProto (protoName
);
2082 * Extract local address.
2084 ptr
= strtok (NULL
, " \t");
2086 errx (1, "redirect_port: missing local address");
2088 separator
= strchr(ptr
, ',');
2089 if (separator
) { /* LSNAT redirection syntax. */
2090 localAddr
.s_addr
= INADDR_NONE
;
2095 if ( StrToAddrAndPortRange (ptr
, &localAddr
, protoName
, &portRange
) != 0 )
2096 errx (1, "redirect_port: invalid local port range");
2098 localPort
= GETLOPORT(portRange
);
2099 numLocalPorts
= GETNUMPORTS(portRange
);
2104 * Extract public port and optionally address.
2106 ptr
= strtok (NULL
, " \t");
2108 errx (1, "redirect_port: missing public port");
2110 separator
= strchr (ptr
, ':');
2112 if (StrToAddrAndPortRange (ptr
, &publicAddr
, protoName
, &portRange
) != 0 )
2113 errx (1, "redirect_port: invalid public port range");
2116 publicAddr
.s_addr
= INADDR_ANY
;
2117 if (StrToPortRange (ptr
, protoName
, &portRange
) != 0)
2118 errx (1, "redirect_port: invalid public port range");
2121 publicPort
= GETLOPORT(portRange
);
2122 numPublicPorts
= GETNUMPORTS(portRange
);
2125 * Extract remote address and optionally port.
2127 ptr
= strtok (NULL
, " \t");
2129 separator
= strchr (ptr
, ':');
2131 if (StrToAddrAndPortRange (ptr
, &remoteAddr
, protoName
, &portRange
) != 0)
2132 errx (1, "redirect_port: invalid remote port range");
2134 SETLOPORT(portRange
, 0);
2135 SETNUMPORTS(portRange
, 1);
2136 StrToAddr (ptr
, &remoteAddr
);
2140 SETLOPORT(portRange
, 0);
2141 SETNUMPORTS(portRange
, 1);
2142 remoteAddr
.s_addr
= INADDR_ANY
;
2145 remotePort
= GETLOPORT(portRange
);
2146 numRemotePorts
= GETNUMPORTS(portRange
);
2149 * Make sure port ranges match up, then add the redirect ports.
2151 if (numLocalPorts
!= numPublicPorts
)
2152 errx (1, "redirect_port: port ranges must be equal in size");
2154 /* Remote port range is allowed to be '0' which means all ports. */
2155 if (numRemotePorts
!= numLocalPorts
&& (numRemotePorts
!= 1 || remotePort
!= 0))
2156 errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
2158 for (i
= 0 ; i
< numPublicPorts
; ++i
) {
2159 /* If remotePort is all ports, set it to 0. */
2160 u_short remotePortCopy
= remotePort
+ i
;
2161 if (numRemotePorts
== 1 && remotePort
== 0)
2164 link
= PacketAliasRedirectPort (localAddr
,
2165 htons(localPort
+ i
),
2167 htons(remotePortCopy
),
2169 htons(publicPort
+ i
),
2174 * Setup LSNAT server pool.
2176 if (serverPool
!= NULL
&& link
!= NULL
) {
2177 ptr
= strtok(serverPool
, ",");
2178 while (ptr
!= NULL
) {
2179 if (StrToAddrAndPortRange(ptr
, &localAddr
, protoName
, &portRange
) != 0)
2180 errx(1, "redirect_port: invalid local port range");
2182 localPort
= GETLOPORT(portRange
);
2183 if (GETNUMPORTS(portRange
) != 1)
2184 errx(1, "redirect_port: local port must be single in this context");
2185 PacketAliasAddServer(link
, localAddr
, htons(localPort
));
2186 ptr
= strtok(NULL
, ",");
2192 SetupProtoRedirect(const char* parms
)
2196 struct in_addr localAddr
;
2197 struct in_addr publicAddr
;
2198 struct in_addr remoteAddr
;
2201 struct protoent
*protoent
;
2203 strlcpy (buf
, parms
, sizeof(buf
));
2207 protoName
= strtok(buf
, " \t");
2209 errx(1, "redirect_proto: missing protocol");
2211 protoent
= getprotobyname(protoName
);
2212 if (protoent
== NULL
)
2213 errx(1, "redirect_proto: unknown protocol %s", protoName
);
2215 proto
= protoent
->p_proto
;
2217 * Extract local address.
2219 ptr
= strtok(NULL
, " \t");
2221 errx(1, "redirect_proto: missing local address");
2223 StrToAddr(ptr
, &localAddr
);
2225 * Extract optional public address.
2227 ptr
= strtok(NULL
, " \t");
2229 StrToAddr(ptr
, &publicAddr
);
2231 publicAddr
.s_addr
= INADDR_ANY
;
2233 * Extract optional remote address.
2235 ptr
= strtok(NULL
, " \t");
2237 StrToAddr(ptr
, &remoteAddr
);
2239 remoteAddr
.s_addr
= INADDR_ANY
;
2241 * Create aliasing link.
2243 (void)PacketAliasRedirectProto(localAddr
, remoteAddr
, publicAddr
,
2247 void SetupAddressRedirect (const char* parms
)
2252 struct in_addr localAddr
;
2253 struct in_addr publicAddr
;
2255 struct alias_link
*link
;
2257 strlcpy (buf
, parms
, sizeof(buf
));
2259 * Extract local address.
2261 ptr
= strtok (buf
, " \t");
2263 errx (1, "redirect_address: missing local address");
2265 separator
= strchr(ptr
, ',');
2266 if (separator
) { /* LSNAT redirection syntax. */
2267 localAddr
.s_addr
= INADDR_NONE
;
2270 StrToAddr (ptr
, &localAddr
);
2274 * Extract public address.
2276 ptr
= strtok (NULL
, " \t");
2278 errx (1, "redirect_address: missing public address");
2280 StrToAddr (ptr
, &publicAddr
);
2281 link
= PacketAliasRedirectAddr(localAddr
, publicAddr
);
2284 * Setup LSNAT server pool.
2286 if (serverPool
!= NULL
&& link
!= NULL
) {
2287 ptr
= strtok(serverPool
, ",");
2288 while (ptr
!= NULL
) {
2289 StrToAddr(ptr
, &localAddr
);
2290 PacketAliasAddServer(link
, localAddr
, htons(~0));
2291 ptr
= strtok(NULL
, ",");
2296 void StrToAddr (const char* str
, struct in_addr
* addr
)
2300 if (inet_aton (str
, addr
))
2303 hp
= gethostbyname (str
);
2305 errx (1, "unknown host %s", str
);
2307 memcpy (addr
, hp
->h_addr
, sizeof (struct in_addr
));
2310 u_short
StrToPort (const char* str
, const char* proto
)
2316 port
= strtol (str
, &end
, 10);
2318 return htons (port
);
2320 sp
= getservbyname (str
, proto
);
2322 errx (1, "unknown service %s/%s", str
, proto
);
2327 int StrToPortRange (const char* str
, const char* proto
, port_range
*portRange
)
2335 /* First see if this is a service, return corresponding port if so. */
2336 sp
= getservbyname (str
,proto
);
2338 SETLOPORT(*portRange
, ntohs(sp
->s_port
));
2339 SETNUMPORTS(*portRange
, 1);
2343 /* Not a service, see if it's a single port or port range. */
2344 sep
= strchr (str
, '-');
2346 SETLOPORT(*portRange
, strtol(str
, &end
, 10));
2349 SETNUMPORTS(*portRange
, 1);
2353 /* Error in port range field. */
2354 errx (1, "unknown service %s/%s", str
, proto
);
2357 /* Port range, get the values and sanity check. */
2358 sscanf (str
, "%hu-%hu", &loPort
, &hiPort
);
2359 SETLOPORT(*portRange
, loPort
);
2360 SETNUMPORTS(*portRange
, 0); /* Error by default */
2361 if (loPort
<= hiPort
)
2362 SETNUMPORTS(*portRange
, hiPort
- loPort
+ 1);
2364 if (GETNUMPORTS(*portRange
) == 0)
2365 errx (1, "invalid port range %s", str
);
2371 int StrToProto (const char* str
)
2373 if (!strcmp (str
, "tcp"))
2376 if (!strcmp (str
, "udp"))
2379 errx (1, "unknown protocol %s. Expected tcp or udp", str
);
2382 int StrToAddrAndPortRange (const char* str
, struct in_addr
* addr
, char* proto
, port_range
*portRange
)
2386 ptr
= strchr (str
, ':');
2388 errx (1, "%s is missing port number", str
);
2393 StrToAddr (str
, addr
);
2394 return StrToPortRange (ptr
, proto
, portRange
);
2398 SetupPunchFW(const char *strValue
)
2400 unsigned int base
, num
;
2402 if (sscanf(strValue
, "%u:%u", &base
, &num
) != 2)
2403 errx(1, "punch_fw: basenumber:count parameter required");
2405 PacketAliasSetFWBase(base
, num
);
2406 (void)PacketAliasSetMode(PKT_ALIAS_PUNCH_FW
, PKT_ALIAS_PUNCH_FW
);