2 * natd - Network Address Translation Daemon for FreeBSD.
4 * This software is provided free of charge, with no
5 * warranty of any kind, either expressed or implied.
6 * Use at your own risk.
8 * You may copy, modify and distribute this software (natd.c) freely.
10 * Ari Suutari <suutari@iki.fi>
12 * $Id: natd.c,v 1.1.1.1 2000/01/11 01:48:51 wsanchez Exp $
17 #include <sys/types.h>
18 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <netinet/in_systm.h>
23 #include <netinet/ip.h>
24 #include <netinet/tcp.h>
25 #include <netinet/udp.h>
26 #include <netinet/ip_icmp.h>
27 #include <sys/ioctl.h>
29 #include <net/route.h>
30 #include <arpa/inet.h>
47 * Default values for input and output
48 * divert socket ports.
51 #define DEFAULT_SERVICE "natd"
54 * Definition of a port range, and macros to deal with values.
55 * FORMAT: HI 16-bits == first port in range, 0 == all ports.
56 * LO 16-bits == number of ports in range
57 * NOTES: - Port values are not stored in network byte order.
60 typedef u_long port_range
;
62 #define GETLOPORT(x) ((x) >> 0x10)
63 #define GETNUMPORTS(x) ((x) & 0x0000ffff)
64 #define GETHIPORT(x) (GETLOPORT((x)) + GETNUMPORTS((x)))
66 /* Set y to be the low-port value in port_range variable x. */
67 #define SETLOPORT(x,y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
69 /* Set y to be the number of ports in port_range variable x. */
70 #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y))
73 * Function prototypes.
76 static void DoAliasing (int fd
, int direction
);
77 static void DaemonMode (void);
78 static void HandleRoutingInfo (int fd
);
79 static void Usage (void);
80 static char* FormatPacket (struct ip
*);
81 static void PrintPacket (struct ip
*);
82 static void SyslogPacket (struct ip
*, int priority
, const char *label
);
83 static void SetAliasAddressFromIfName (char* ifName
);
84 static void InitiateShutdown (int);
85 static void Shutdown (int);
86 static void RefreshAddr (int);
87 static void ParseOption (const char* option
, const char* parms
, int cmdLine
);
88 static void ReadConfigFile (const char* fileName
);
89 static void SetupPortRedirect (const char* parms
);
90 static void SetupAddressRedirect (const char* parms
);
91 static void SetupPptpAlias (const char* parms
);
92 static void StrToAddr (const char* str
, struct in_addr
* addr
);
93 static u_short
StrToPort (const char* str
, const char* proto
);
94 static int StrToPortRange (const char* str
, const char* proto
, port_range
*portRange
);
95 static int StrToProto (const char* str
);
96 static int StrToAddrAndPortRange (const char* str
, struct in_addr
* addr
, char* proto
, port_range
*portRange
);
97 static void ParseArgs (int argc
, char** argv
);
98 static void FlushPacketBuffer (int fd
);
105 static int background
;
107 static int assignAliasAddr
;
110 static u_short inPort
;
111 static u_short outPort
;
112 static u_short inOutPort
;
113 static struct in_addr aliasAddr
;
114 static int dynamicMode
;
116 static int aliasOverhead
;
118 static char packetBuf
[IP_MAXPACKET
];
119 static int packetLen
;
120 static struct sockaddr_in packetAddr
;
121 static int packetSock
;
122 static int packetDirection
;
123 static int dropIgnoredIncoming
;
124 static int logDropped
;
125 static int logFacility
;
127 int main (int argc
, char** argv
)
133 struct sockaddr_in addr
;
138 * Initialize packet aliasing software.
139 * Done already here to be able to alter option bits
140 * during command line and configuration file processing.
155 aliasAddr
.s_addr
= INADDR_NONE
;
159 logFacility
= LOG_DAEMON
;
161 * Mark packet buffer empty.
164 packetDirection
= DONT_KNOW
;
166 ParseArgs (argc
, argv
);
168 * Open syslog channel.
170 openlog ("natd", LOG_CONS
| LOG_PID
, logFacility
);
172 * Check that valid aliasing address has been given.
174 if (aliasAddr
.s_addr
== INADDR_NONE
&& ifName
== NULL
)
175 errx (1, "aliasing address not given");
177 if (aliasAddr
.s_addr
!= INADDR_NONE
&& ifName
!= NULL
)
178 errx (1, "both alias address and interface "
179 "name are not allowed");
181 * Check that valid port number is known.
183 if (inPort
!= 0 || outPort
!= 0)
184 if (inPort
== 0 || outPort
== 0)
185 errx (1, "both input and output ports are required");
187 if (inPort
== 0 && outPort
== 0 && inOutPort
== 0)
188 ParseOption ("port", DEFAULT_SERVICE
, 0);
191 * Check if ignored packets should be dropped.
193 dropIgnoredIncoming
= PacketAliasSetMode (0, 0);
194 dropIgnoredIncoming
&= PKT_ALIAS_DENY_INCOMING
;
196 * Create divert sockets. Use only one socket if -p was specified
197 * on command line. Otherwise, create separate sockets for
198 * outgoing and incoming connnections.
202 divertInOut
= socket (PF_INET
, SOCK_RAW
, IPPROTO_DIVERT
);
203 if (divertInOut
== -1)
204 Quit ("Unable to create divert socket.");
212 addr
.sin_family
= AF_INET
;
213 addr
.sin_addr
.s_addr
= INADDR_ANY
;
214 addr
.sin_port
= inOutPort
;
216 if (bind (divertInOut
,
217 (struct sockaddr
*) &addr
,
219 Quit ("Unable to bind divert socket.");
223 divertIn
= socket (PF_INET
, SOCK_RAW
, IPPROTO_DIVERT
);
225 Quit ("Unable to create incoming divert socket.");
227 divertOut
= socket (PF_INET
, SOCK_RAW
, IPPROTO_DIVERT
);
229 Quit ("Unable to create outgoing divert socket.");
234 * Bind divert sockets.
237 addr
.sin_family
= AF_INET
;
238 addr
.sin_addr
.s_addr
= INADDR_ANY
;
239 addr
.sin_port
= inPort
;
242 (struct sockaddr
*) &addr
,
244 Quit ("Unable to bind incoming divert socket.");
246 addr
.sin_family
= AF_INET
;
247 addr
.sin_addr
.s_addr
= INADDR_ANY
;
248 addr
.sin_port
= outPort
;
251 (struct sockaddr
*) &addr
,
253 Quit ("Unable to bind outgoing divert socket.");
256 * Create routing socket if interface name specified.
258 if (ifName
&& dynamicMode
) {
260 routeSock
= socket (PF_ROUTE
, SOCK_RAW
, 0);
262 Quit ("Unable to create routing info socket.");
267 * Create socket for sending ICMP messages.
269 icmpSock
= socket (AF_INET
, SOCK_RAW
, IPPROTO_ICMP
);
271 Quit ("Unable to create ICMP socket.");
274 * And disable reads for the socket, otherwise it slowly fills
275 * up with received icmps which we do not use.
277 shutdown(icmpSock
, SHUT_RD
);
280 * Become a daemon unless verbose mode was requested.
285 * Catch signals to manage shutdown and
286 * refresh of interface address.
288 signal (SIGTERM
, InitiateShutdown
);
289 signal (SIGHUP
, RefreshAddr
);
291 * Set alias address if it has been given.
293 if (aliasAddr
.s_addr
!= INADDR_NONE
)
294 PacketAliasSetAddress (aliasAddr
);
296 * We need largest descriptor number for select.
301 if (divertIn
> fdMax
)
304 if (divertOut
> fdMax
)
307 if (divertInOut
> fdMax
)
310 if (routeSock
> fdMax
)
315 if (divertInOut
!= -1 && !ifName
&& packetSock
== -1) {
317 * When using only one socket, just call
318 * DoAliasing repeatedly to process packets.
320 DoAliasing (divertInOut
, DONT_KNOW
);
324 * Build read mask from socket descriptors to select.
327 FD_ZERO (&writeMask
);
330 * If there is unsent packet in buffer, use select
331 * to check when socket comes writable again.
333 if (packetSock
!= -1) {
335 FD_SET (packetSock
, &writeMask
);
339 * No unsent packet exists - safe to check if
340 * new ones are available.
343 FD_SET (divertIn
, &readMask
);
346 FD_SET (divertOut
, &readMask
);
348 if (divertInOut
!= -1)
349 FD_SET (divertInOut
, &readMask
);
352 * Routing info is processed always.
355 FD_SET (routeSock
, &readMask
);
357 if (select (fdMax
+ 1,
366 Quit ("Select failed.");
369 if (packetSock
!= -1)
370 if (FD_ISSET (packetSock
, &writeMask
))
371 FlushPacketBuffer (packetSock
);
374 if (FD_ISSET (divertIn
, &readMask
))
375 DoAliasing (divertIn
, INPUT
);
378 if (FD_ISSET (divertOut
, &readMask
))
379 DoAliasing (divertOut
, OUTPUT
);
381 if (divertInOut
!= -1)
382 if (FD_ISSET (divertInOut
, &readMask
))
383 DoAliasing (divertInOut
, DONT_KNOW
);
386 if (FD_ISSET (routeSock
, &readMask
))
387 HandleRoutingInfo (routeSock
);
396 static void DaemonMode ()
403 pidFile
= fopen (PIDFILE
, "w");
406 fprintf (pidFile
, "%d\n", getpid ());
411 static void ParseArgs (int argc
, char** argv
)
418 for (arg
= 1; arg
< argc
; arg
++) {
423 warnx ("invalid option %s", opt
);
430 while (arg
< argc
- 1) {
432 if (argv
[arg
+ 1][0] == '-')
436 strcat (parmBuf
, " ");
440 strcat (parmBuf
, argv
[arg
]);
443 ParseOption (opt
+ 1, parm
, 1);
447 static void DoAliasing (int fd
, int direction
)
455 if (assignAliasAddr
) {
457 SetAliasAddressFromIfName (ifName
);
461 * Get packet from socket.
463 addrSize
= sizeof packetAddr
;
464 origBytes
= recvfrom (fd
,
468 (struct sockaddr
*) &packetAddr
,
471 if (origBytes
== -1) {
474 Warn ("read from divert socket failed");
479 * This is a IP packet.
481 ip
= (struct ip
*) packetBuf
;
482 if (direction
== DONT_KNOW
)
483 if (packetAddr
.sin_addr
.s_addr
== INADDR_ANY
)
491 * Print packet direction and protocol type.
493 printf (direction
== OUTPUT
? "Out " : "In ");
509 printf ("[%d] ", ip
->ip_p
);
518 if (direction
== OUTPUT
) {
520 * Outgoing packets. Do aliasing.
522 PacketAliasOut (packetBuf
, IP_MAXPACKET
);
529 status
= PacketAliasIn (packetBuf
, IP_MAXPACKET
);
530 if (status
== PKT_ALIAS_IGNORED
&&
531 dropIgnoredIncoming
) {
534 printf (" dropped.\n");
537 SyslogPacket (ip
, LOG_WARNING
, "denied");
543 * Length might have changed during aliasing.
545 bytes
= ntohs (ip
->ip_len
);
547 * Update alias overhead size for outgoing packets.
549 if (direction
== OUTPUT
&&
550 bytes
- origBytes
> aliasOverhead
)
551 aliasOverhead
= bytes
- origBytes
;
556 * Print addresses after aliasing.
558 printf (" aliased to\n");
566 packetDirection
= direction
;
568 FlushPacketBuffer (fd
);
571 static void FlushPacketBuffer (int fd
)
576 * Put packet back for processing.
582 (struct sockaddr
*) &packetAddr
,
585 if (wrote
!= packetLen
) {
587 * If buffer space is not available,
588 * just return. Main loop will take care of
589 * retrying send when space becomes available.
591 if (errno
== ENOBUFS
)
594 if (errno
== EMSGSIZE
) {
596 if (packetDirection
== OUTPUT
&&
598 SendNeedFragIcmp (icmpSock
,
599 (struct ip
*) packetBuf
,
600 ifMTU
- aliasOverhead
);
604 sprintf (msgBuf
, "failed to write packet back");
612 static void HandleRoutingInfo (int fd
)
615 struct if_msghdr ifMsg
;
617 * Get packet from socket.
619 bytes
= read (fd
, &ifMsg
, sizeof ifMsg
);
622 Warn ("read from routing socket failed");
626 if (ifMsg
.ifm_version
!= RTM_VERSION
) {
628 Warn ("unexpected packet read from routing socket");
633 printf ("Routing message %X received.\n", ifMsg
.ifm_type
);
635 if (ifMsg
.ifm_type
!= RTM_NEWADDR
)
638 if (verbose
&& ifMsg
.ifm_index
== ifIndex
)
639 printf ("Interface address has changed.\n");
641 if (ifMsg
.ifm_index
== ifIndex
)
645 static void PrintPacket (struct ip
* ip
)
647 printf ("%s", FormatPacket (ip
));
650 static void SyslogPacket (struct ip
* ip
, int priority
, const char *label
)
652 syslog (priority
, "%s %s", label
, FormatPacket (ip
));
655 static char* FormatPacket (struct ip
* ip
)
657 static char buf
[256];
658 struct tcphdr
* tcphdr
;
659 struct udphdr
* udphdr
;
660 struct icmp
* icmphdr
;
664 strcpy (src
, inet_ntoa (ip
->ip_src
));
665 strcpy (dst
, inet_ntoa (ip
->ip_dst
));
669 tcphdr
= (struct tcphdr
*) ((char*) ip
+ (ip
->ip_hl
<< 2));
670 sprintf (buf
, "[TCP] %s:%d -> %s:%d",
672 ntohs (tcphdr
->th_sport
),
674 ntohs (tcphdr
->th_dport
));
678 udphdr
= (struct udphdr
*) ((char*) ip
+ (ip
->ip_hl
<< 2));
679 sprintf (buf
, "[UDP] %s:%d -> %s:%d",
681 ntohs (udphdr
->uh_sport
),
683 ntohs (udphdr
->uh_dport
));
687 icmphdr
= (struct icmp
*) ((char*) ip
+ (ip
->ip_hl
<< 2));
688 sprintf (buf
, "[ICMP] %s -> %s %u(%u)",
696 sprintf (buf
, "[%d] %s -> %s ", ip
->ip_p
, src
, dst
);
703 static void SetAliasAddressFromIfName (char* ifn
)
706 struct ifreq buf
[32];
712 struct sockaddr_in
* addr
;
717 * Create a dummy socket to access interface information.
719 helperSock
= socket (AF_INET
, SOCK_DGRAM
, 0);
720 if (helperSock
== -1) {
722 Quit ("Failed to create helper socket.");
726 cf
.ifc_len
= sizeof (buf
);
729 * Get interface data.
731 if (ioctl (helperSock
, SIOCGIFCONF
, &cf
) == -1) {
733 Quit ("Ioctl SIOCGIFCONF failed.");
743 * Loop through interfaces until one with
744 * given name is found. This is done to
745 * find correct interface index for routing
746 * message processing.
750 if (ifPtr
->ifr_addr
.sa_family
== AF_INET
&&
751 !strcmp (ifPtr
->ifr_name
, ifn
)) {
757 if (strcmp (last
, ifPtr
->ifr_name
)) {
759 strcpy (last
, ifPtr
->ifr_name
);
763 extra
= ifPtr
->ifr_addr
.sa_len
- sizeof (struct sockaddr
);
766 ifPtr
= (struct ifreq
*) ((char*) ifPtr
+ extra
);
767 bytes
-= sizeof (struct ifreq
) + extra
;
773 sprintf (msg
, "Unknown interface name %s.\n", ifn
);
779 strcpy (req
.ifr_name
, ifn
);
781 if (ioctl (helperSock
, SIOCGIFMTU
, &req
) == -1)
782 Quit ("Cannot get interface mtu size.");
786 * Get interface address.
788 if (ioctl (helperSock
, SIOCGIFADDR
, &req
) == -1)
789 Quit ("Cannot get interface address.");
791 addr
= (struct sockaddr_in
*) &req
.ifr_addr
;
792 PacketAliasSetAddress (addr
->sin_addr
);
793 syslog (LOG_INFO
, "Aliasing to %s, mtu %d bytes",
794 inet_ntoa (addr
->sin_addr
),
800 void Quit (const char* msg
)
806 void Warn (const char* msg
)
809 syslog (LOG_ALERT
, "%s (%m)", msg
);
814 static void RefreshAddr (int sig
)
816 signal (SIGHUP
, RefreshAddr
);
821 static void InitiateShutdown (int sig
)
824 * Start timer to allow kernel gracefully
825 * shutdown existing connections when system
828 signal (SIGALRM
, Shutdown
);
832 static void Shutdown (int sig
)
838 * Different options recognized by this program.
871 * Option information structure (used by ParseOption).
879 const char* parmDescription
;
880 const char* description
;
882 const char* shortName
;
886 * Table of known options.
889 static struct OptionInfo optionTable
[] = {
892 PKT_ALIAS_UNREGISTERED_ONLY
,
895 "alias only unregistered addresses",
908 PKT_ALIAS_PROXY_ONLY
,
919 "operate in reverse mode",
924 PKT_ALIAS_DENY_INCOMING
,
927 "allow incoming connections",
932 PKT_ALIAS_USE_SOCKETS
,
935 "use sockets to inhibit port conflict",
940 PKT_ALIAS_SAME_PORTS
,
943 "try to keep original port numbers for connections",
951 "verbose mode, dump packet information",
959 "dynamic mode, automatically detect interface address changes",
966 "number|service_name",
967 "set port for incoming packets",
974 "number|service_name",
975 "set port for outgoing packets",
982 "number|service_name",
983 "set port (defaults to natd/divert)",
991 "address to use for aliasing",
999 "take aliasing address from interface",
1006 "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
1008 "add transparent proxying / destination NAT",
1015 "tcp|udp local_addr:local_port_range [public_addr:]public_port_range"
1016 " [remote_addr[:remote_port_range]]",
1017 "redirect a port (or ports) for incoming traffic",
1024 "local_addr public_addr",
1025 "define mapping between local and public addresses",
1033 "define inside machine for PPTP traffic",
1041 "read options from configuration file",
1049 "enable logging of denied incoming packets",
1057 "name of syslog facility to use for logging",
1063 static void ParseOption (const char* option
, const char* parms
, int cmdLine
)
1066 struct OptionInfo
* info
;
1071 const char* strValue
;
1072 struct in_addr addrValue
;
1075 CODE
* fac_record
= NULL
;
1077 * Find option from table.
1079 max
= sizeof (optionTable
) / sizeof (struct OptionInfo
);
1080 for (i
= 0, info
= optionTable
; i
< max
; i
++, info
++) {
1082 if (!strcmp (info
->name
, option
))
1085 if (info
->shortName
)
1086 if (!strcmp (info
->shortName
, option
))
1092 warnx ("unknown option %s", option
);
1103 switch (info
->parm
) {
1108 if (!strcmp (parms
, "yes"))
1111 if (!strcmp (parms
, "no"))
1114 errx (1, "%s needs yes/no parameter", option
);
1119 errx (1, "%s needs service name or "
1120 "port number parameter",
1123 uNumValue
= StrToPort (parms
, "divert");
1128 numValue
= strtol (parms
, &end
, 10);
1133 errx (1, "%s needs numeric parameter", option
);
1139 errx (1, "%s needs parameter", option
);
1144 errx (1, "%s does not take parameters", option
);
1149 errx (1, "%s needs address/host parameter", option
);
1151 StrToAddr (parms
, &addrValue
);
1155 switch (info
->type
) {
1156 case PacketAliasOption
:
1158 aliasValue
= yesNoValue
? info
->packetAliasOpt
: 0;
1159 PacketAliasSetMode (aliasValue
, info
->packetAliasOpt
);
1163 verbose
= yesNoValue
;
1167 dynamicMode
= yesNoValue
;
1175 outPort
= uNumValue
;
1179 inOutPort
= uNumValue
;
1183 memcpy (&aliasAddr
, &addrValue
, sizeof (struct in_addr
));
1187 SetupPortRedirect (strValue
);
1190 case RedirectAddress
:
1191 SetupAddressRedirect (strValue
);
1195 SetupPptpAlias (strValue
);
1199 PacketAliasProxyRule (strValue
);
1206 ifName
= strdup (strValue
);
1207 assignAliasAddr
= 1;
1211 ReadConfigFile (strValue
);
1220 fac_record
= facilitynames
;
1221 while (fac_record
->c_name
!= NULL
) {
1223 if (!strcmp (fac_record
->c_name
, strValue
)) {
1225 logFacility
= fac_record
->c_val
;
1233 if(fac_record
->c_name
== NULL
)
1234 errx(1, "Unknown log facility name: %s", strValue
);
1240 void ReadConfigFile (const char* fileName
)
1247 file
= fopen (fileName
, "r");
1250 sprintf (buf
, "Cannot open config file %s.\n", fileName
);
1254 while (fgets (buf
, sizeof (buf
), file
)) {
1256 ptr
= strchr (buf
, '\n');
1258 errx (1, "config line too long: %s", buf
);
1266 * Skip white space at beginning of line.
1268 while (*ptr
&& isspace (*ptr
))
1274 * Extract option name.
1277 while (*ptr
&& !isspace (*ptr
))
1286 * Skip white space between name and parms.
1288 while (*ptr
&& isspace (*ptr
))
1291 ParseOption (option
, *ptr
? ptr
: NULL
, 0);
1297 static void Usage ()
1301 struct OptionInfo
* info
;
1303 fprintf (stderr
, "Recognized options:\n\n");
1305 max
= sizeof (optionTable
) / sizeof (struct OptionInfo
);
1306 for (i
= 0, info
= optionTable
; i
< max
; i
++, info
++) {
1308 fprintf (stderr
, "-%-20s %s\n", info
->name
,
1309 info
->parmDescription
);
1311 if (info
->shortName
)
1312 fprintf (stderr
, "-%-20s %s\n", info
->shortName
,
1313 info
->parmDescription
);
1315 fprintf (stderr
, " %s\n\n", info
->description
);
1321 void SetupPptpAlias (const char* parms
)
1325 struct in_addr srcAddr
;
1327 strcpy (buf
, parms
);
1330 * Extract source address.
1332 ptr
= strtok (buf
, " \t");
1334 errx(1, "pptpalias: missing src address");
1336 StrToAddr (ptr
, &srcAddr
);
1337 PacketAliasPptp (srcAddr
);
1340 void SetupPortRedirect (const char* parms
)
1344 struct in_addr localAddr
;
1345 struct in_addr publicAddr
;
1346 struct in_addr remoteAddr
;
1347 port_range portRange
;
1348 u_short localPort
= 0;
1349 u_short publicPort
= 0;
1350 u_short remotePort
= 0;
1351 u_short numLocalPorts
= 0;
1352 u_short numPublicPorts
= 0;
1353 u_short numRemotePorts
= 0;
1359 strcpy (buf
, parms
);
1363 protoName
= strtok (buf
, " \t");
1365 errx (1, "redirect_port: missing protocol");
1367 proto
= StrToProto (protoName
);
1369 * Extract local address.
1371 ptr
= strtok (NULL
, " \t");
1373 errx (1, "redirect_port: missing local address");
1375 if ( StrToAddrAndPortRange (ptr
, &localAddr
, protoName
, &portRange
) != 0 )
1376 errx (1, "redirect_port: invalid local port range");
1378 localPort
= GETLOPORT(portRange
);
1379 numLocalPorts
= GETNUMPORTS(portRange
);
1382 * Extract public port and optinally address.
1384 ptr
= strtok (NULL
, " \t");
1386 errx (1, "redirect_port: missing public port");
1388 separator
= strchr (ptr
, ':');
1390 if (StrToAddrAndPortRange (ptr
, &publicAddr
, protoName
, &portRange
) != 0 )
1391 errx (1, "redirect_port: invalid public port range");
1394 publicAddr
.s_addr
= INADDR_ANY
;
1395 if (StrToPortRange (ptr
, protoName
, &portRange
) != 0)
1396 errx (1, "redirect_port: invalid public port range");
1399 publicPort
= GETLOPORT(portRange
);
1400 numPublicPorts
= GETNUMPORTS(portRange
);
1403 * Extract remote address and optionally port.
1405 ptr
= strtok (NULL
, " \t");
1407 separator
= strchr (ptr
, ':');
1409 if (StrToAddrAndPortRange (ptr
, &remoteAddr
, protoName
, &portRange
) != 0)
1410 errx (1, "redirect_port: invalid remote port range");
1412 SETLOPORT(portRange
, 0);
1413 SETNUMPORTS(portRange
, 1);
1414 StrToAddr (ptr
, &remoteAddr
);
1418 SETLOPORT(portRange
, 0);
1419 SETNUMPORTS(portRange
, 1);
1420 remoteAddr
.s_addr
= INADDR_ANY
;
1423 remotePort
= GETLOPORT(portRange
);
1424 numRemotePorts
= GETNUMPORTS(portRange
);
1427 * Make sure port ranges match up, then add the redirect ports.
1429 if (numLocalPorts
!= numPublicPorts
)
1430 errx (1, "redirect_port: port ranges must be equal in size");
1432 /* Remote port range is allowed to be '0' which means all ports. */
1433 if (numRemotePorts
!= numLocalPorts
&& numRemotePorts
!= 1 && remotePort
!= 0)
1434 errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
1436 for (i
= 0 ; i
< numPublicPorts
; ++i
) {
1437 /* If remotePort is all ports, set it to 0. */
1438 u_short remotePortCopy
= remotePort
+ i
;
1439 if (numRemotePorts
== 1 && remotePort
== 0)
1442 PacketAliasRedirectPort (localAddr
,
1443 htons(localPort
+ i
),
1445 htons(remotePortCopy
),
1447 htons(publicPort
+ i
),
1452 void SetupAddressRedirect (const char* parms
)
1456 struct in_addr localAddr
;
1457 struct in_addr publicAddr
;
1459 strcpy (buf
, parms
);
1461 * Extract local address.
1463 ptr
= strtok (buf
, " \t");
1465 errx (1, "redirect_address: missing local address");
1467 StrToAddr (ptr
, &localAddr
);
1469 * Extract public address.
1471 ptr
= strtok (NULL
, " \t");
1473 errx (1, "redirect_address: missing public address");
1475 StrToAddr (ptr
, &publicAddr
);
1476 PacketAliasRedirectAddr (localAddr
, publicAddr
);
1479 void StrToAddr (const char* str
, struct in_addr
* addr
)
1483 if (inet_aton (str
, addr
))
1486 hp
= gethostbyname (str
);
1488 errx (1, "unknown host %s", str
);
1490 memcpy (addr
, hp
->h_addr
, sizeof (struct in_addr
));
1493 u_short
StrToPort (const char* str
, const char* proto
)
1499 port
= strtol (str
, &end
, 10);
1501 return htons (port
);
1503 sp
= getservbyname (str
, proto
);
1505 errx (1, "unknown service %s/%s", str
, proto
);
1510 int StrToPortRange (const char* str
, const char* proto
, port_range
*portRange
)
1518 /* First see if this is a service, return corresponding port if so. */
1519 sp
= getservbyname (str
,proto
);
1521 SETLOPORT(*portRange
, ntohs(sp
->s_port
));
1522 SETNUMPORTS(*portRange
, 1);
1526 /* Not a service, see if it's a single port or port range. */
1527 sep
= strchr (str
, '-');
1529 SETLOPORT(*portRange
, strtol(str
, &end
, 10));
1532 SETNUMPORTS(*portRange
, 1);
1536 /* Error in port range field. */
1537 errx (1, "unknown service %s/%s", str
, proto
);
1540 /* Port range, get the values and sanity check. */
1541 sscanf (str
, "%hu-%hu", &loPort
, &hiPort
);
1542 SETLOPORT(*portRange
, loPort
);
1543 SETNUMPORTS(*portRange
, 0); /* Error by default */
1544 if (loPort
<= hiPort
)
1545 SETNUMPORTS(*portRange
, hiPort
- loPort
+ 1);
1547 if (GETNUMPORTS(*portRange
) == 0)
1548 errx (1, "invalid port range %s", str
);
1554 int StrToProto (const char* str
)
1556 if (!strcmp (str
, "tcp"))
1559 if (!strcmp (str
, "udp"))
1562 errx (1, "unknown protocol %s. Expected tcp or udp", str
);
1565 int StrToAddrAndPortRange (const char* str
, struct in_addr
* addr
, char* proto
, port_range
*portRange
)
1569 ptr
= strchr (str
, ':');
1571 errx (1, "%s is missing port number", str
);
1576 StrToAddr (str
, addr
);
1577 return StrToPortRange (ptr
, proto
, portRange
);