]> git.saurik.com Git - apple/network_cmds.git/blame - natd.tproj/natd.c
network_cmds-511.50.3.tar.gz
[apple/network_cmds.git] / natd.tproj / natd.c
CommitLineData
7ba0088d 1/*
fdfd5971 2 * Copyright (c) 2000-2009 Apple Inc. All rights reserved.
7ba0088d 3 *
fdfd5971
A
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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
7ba0088d
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
fdfd5971
A
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
7ba0088d 27 */
fdfd5971 28
b7080c8e
A
29/*
30 * natd - Network Address Translation Daemon for FreeBSD.
31 *
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.
35 *
36 * You may copy, modify and distribute this software (natd.c) freely.
37 *
38 * Ari Suutari <suutari@iki.fi>
39 *
7ba0088d
A
40 * Based upon:
41 * $FreeBSD: src/sbin/natd/natd.c,v 1.25.2.3 2000/07/11 20:00:57 ru Exp $
b7080c8e
A
42 */
43
44#define SYSLOG_NAMES
45
46#include <sys/types.h>
47#include <sys/socket.h>
2b484d24
A
48#include <net/if.h>
49#include <ifaddrs.h>
7ba0088d 50#include <sys/sysctl.h>
b7080c8e
A
51#include <sys/time.h>
52
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>
b7080c8e 59#include <net/if.h>
7ba0088d 60#include <net/if_dl.h>
b7080c8e
A
61#include <net/route.h>
62#include <arpa/inet.h>
63
64#include <alias.h>
9c859447
A
65void DumpInfo(void);
66
b7080c8e
A
67#include <ctype.h>
68#include <err.h>
69#include <errno.h>
70#include <netdb.h>
71#include <signal.h>
72#include <stdio.h>
73#include <stdlib.h>
74#include <string.h>
75#include <syslog.h>
76#include <unistd.h>
9c859447 77#include <fcntl.h>
2b484d24
A
78#include <mach/mach_time.h>
79#include <mach/clock_types.h>
b7080c8e
A
80
81#include "natd.h"
82
83/*
84 * Default values for input and output
85 * divert socket ports.
86 */
87
88#define DEFAULT_SERVICE "natd"
89
90/*
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.
95 */
96
9c859447 97typedef uint32_t port_range;
b7080c8e
A
98
99#define GETLOPORT(x) ((x) >> 0x10)
100#define GETNUMPORTS(x) ((x) & 0x0000ffff)
101#define GETHIPORT(x) (GETLOPORT((x)) + GETNUMPORTS((x)))
102
103/* Set y to be the low-port value in port_range variable x. */
104#define SETLOPORT(x,y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
105
106/* Set y to be the number of ports in port_range variable x. */
107#define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y))
108
109/*
110 * Function prototypes.
111 */
112
113static void DoAliasing (int fd, int direction);
114static void DaemonMode (void);
115static void HandleRoutingInfo (int fd);
116static void Usage (void);
117static char* FormatPacket (struct ip*);
118static void PrintPacket (struct ip*);
119static void SyslogPacket (struct ip*, int priority, const char *label);
7ba0088d 120static void SetAliasAddressFromIfName (const char *ifName);
b7080c8e
A
121static void InitiateShutdown (int);
122static void Shutdown (int);
123static void RefreshAddr (int);
f47db663 124static void HandleInfo (int);
7ba0088d 125static void ParseOption (const char* option, const char* parms);
b7080c8e
A
126static void ReadConfigFile (const char* fileName);
127static void SetupPortRedirect (const char* parms);
7ba0088d 128static void SetupProtoRedirect(const char* parms);
b7080c8e 129static void SetupAddressRedirect (const char* parms);
b7080c8e
A
130static void StrToAddr (const char* str, struct in_addr* addr);
131static u_short StrToPort (const char* str, const char* proto);
132static int StrToPortRange (const char* str, const char* proto, port_range *portRange);
133static int StrToProto (const char* str);
134static int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange);
135static void ParseArgs (int argc, char** argv);
136static void FlushPacketBuffer (int fd);
9c859447 137static void DiscardIncomingPackets (int fd);
7ba0088d 138static void SetupPunchFW(const char *strValue);
b7080c8e
A
139
140/*
141 * Globals.
142 */
143
144static int verbose;
145static int background;
146static int running;
147static int assignAliasAddr;
148static char* ifName;
149static int ifIndex;
150static u_short inPort;
151static u_short outPort;
152static u_short inOutPort;
153static struct in_addr aliasAddr;
154static int dynamicMode;
285dd90c 155static int clampMSS;
b7080c8e
A
156static int ifMTU;
157static int aliasOverhead;
158static int icmpSock;
159static char packetBuf[IP_MAXPACKET];
160static int packetLen;
161static struct sockaddr_in packetAddr;
162static int packetSock;
163static int packetDirection;
164static int dropIgnoredIncoming;
165static int logDropped;
166static int logFacility;
f47db663 167static int dumpinfo;
b7080c8e 168
2b484d24
A
169#define NATPORTMAP 1
170
171#ifdef NATPORTMAP
9c859447
A
172
173/*
174 * Note: more details on NAT-PMP can be found at :
175 * <http://files.dns-sd.org/draft-cheshire-nat-pmp.txt>
176 */
177
178#define NATPMP_ANNOUNCEMENT_PORT 5350
179#define NATPMP_PORT 5351
2b484d24
A
180
181#define NATPMVERSION 0
182#define PUBLICADDRREQ 0
183#define MAPUDPREQ 1
184#define MAPTCPREQ 2
185#define MAPUDPTCPREQ 3
186#define SERVERREPLYOP 128
2b484d24
A
187
188#define SUCCESS 0
189#define NOTSUPPORTEDVERSION 1
190#define NOTAUTHORIZED 2
191#define NETWORKFAILURE 3
192#define OUTOFRESOURCES 4
193#define UNSUPPORTEDOPCODE 5
9c859447 194
2b484d24 195#define MAXRETRY 10
f47db663 196#define TIMER_RATE 250000
2b484d24
A
197
198#define FAILED -1
199
f47db663 200typedef struct stdportmaprequest {
9c859447
A
201 uint8_t version;
202 uint8_t opcode;
f47db663
A
203} stdportmaprequest;
204
f47db663 205typedef struct publicportreq {
9c859447
A
206 uint8_t version;
207 uint8_t opcode;
208 uint16_t reserved;
209 uint16_t privateport;
210 uint16_t publicport;
211 uint32_t lifetime; /* in seconds */
f47db663
A
212} publicportreq;
213
9c859447
A
214typedef struct publicaddrreply {
215 uint8_t version;
216 uint8_t opcode;
217 uint16_t result;
218 uint32_t epoch;
219 struct in_addr addr;
220} publicaddrreply;
221
f47db663 222typedef struct publicportreply {
9c859447
A
223 uint8_t version;
224 uint8_t opcode;
225 uint16_t result;
226 uint32_t epoch;
227 uint16_t privateport;
228 uint16_t publicport;
229 uint32_t lifetime; /* in seconds */
f47db663
A
230} publicportreply;
231
232typedef struct stderrreply {
9c859447
A
233 uint8_t version;
234 uint8_t opcode;
235 uint16_t result;
236 uint32_t epoch;
f47db663 237} stderrreply;
2b484d24
A
238
239
240static int enable_natportmap = 0;
241static struct in_addr lastassignaliasAddr;
242static int portmapSock = -1;
243static struct in_addr *forwardedinterfaceaddr;
244static char **forwardedinterfacename;
245static int numofinterfaces = 0; /* has to be at least one */
2b484d24
A
246static int numoftries=MAXRETRY;
247static struct itimerval itval;
248static int Natdtimerset = 0;
249static double secdivisor;
250
251
252static void HandlePortMap( int fd );
253static void SendPortMapResponse( int fd, struct sockaddr_in *clientaddr, int clientaddrlen, unsigned char origopcode, unsigned short result);
254static void SendPublicAddress( int fd, struct sockaddr_in *clientaddr, int clientaddrlen );
f47db663 255static void SendPublicPortResponse( int fd, struct sockaddr_in *clientaddr, int clientaddrlen, publicportreq *reply, u_short publicport, int result);
2b484d24
A
256static void Doubletime( struct timeval *tvp);
257static void Stoptimer();
258static void Natdtimer();
259static void SendPortMapMulti( );
260static void NotifyPublicAddress();
261static void DoPortMapping( int fd, struct sockaddr_in *clientaddr, int clientaddrlen, publicportreq *req);
262static void NatPortMapPInit();
2b484d24
A
263
264extern 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);
265
9c859447 266#endif /* NATPORTMAP */
2b484d24 267
b7080c8e
A
268int main (int argc, char** argv)
269{
270 int divertIn;
271 int divertOut;
272 int divertInOut;
273 int routeSock;
274 struct sockaddr_in addr;
275 fd_set readMask;
276 fd_set writeMask;
277 int fdMax;
9c859447 278 int fdFlags;
b7080c8e
A
279/*
280 * Initialize packet aliasing software.
281 * Done already here to be able to alter option bits
282 * during command line and configuration file processing.
283 */
284 PacketAliasInit ();
285/*
286 * Parse options.
287 */
288 inPort = 0;
289 outPort = 0;
290 verbose = 0;
291 inOutPort = 0;
292 ifName = NULL;
293 ifMTU = -1;
294 background = 0;
295 running = 1;
296 assignAliasAddr = 0;
297 aliasAddr.s_addr = INADDR_NONE;
2b484d24
A
298#ifdef NATPORTMAP
299 lastassignaliasAddr.s_addr = INADDR_NONE;
300#endif
b7080c8e
A
301 aliasOverhead = 12;
302 dynamicMode = 0;
303 logDropped = 0;
304 logFacility = LOG_DAEMON;
305/*
306 * Mark packet buffer empty.
307 */
308 packetSock = -1;
309 packetDirection = DONT_KNOW;
310
311 ParseArgs (argc, argv);
312/*
313 * Open syslog channel.
314 */
7ba0088d
A
315 openlog ("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0),
316 logFacility);
b7080c8e
A
317/*
318 * Check that valid aliasing address has been given.
319 */
320 if (aliasAddr.s_addr == INADDR_NONE && ifName == NULL)
321 errx (1, "aliasing address not given");
322
b7080c8e
A
323/*
324 * Check that valid port number is known.
325 */
326 if (inPort != 0 || outPort != 0)
327 if (inPort == 0 || outPort == 0)
328 errx (1, "both input and output ports are required");
329
330 if (inPort == 0 && outPort == 0 && inOutPort == 0)
7ba0088d 331 ParseOption ("port", DEFAULT_SERVICE);
b7080c8e
A
332
333/*
334 * Check if ignored packets should be dropped.
335 */
336 dropIgnoredIncoming = PacketAliasSetMode (0, 0);
337 dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING;
338/*
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.
342 */
343 if (inOutPort) {
344
345 divertInOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
346 if (divertInOut == -1)
347 Quit ("Unable to create divert socket.");
348
349 divertIn = -1;
350 divertOut = -1;
351/*
352 * Bind socket.
353 */
354
355 addr.sin_family = AF_INET;
356 addr.sin_addr.s_addr = INADDR_ANY;
357 addr.sin_port = inOutPort;
358
359 if (bind (divertInOut,
360 (struct sockaddr*) &addr,
361 sizeof addr) == -1)
362 Quit ("Unable to bind divert socket.");
363 }
364 else {
365
366 divertIn = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
367 if (divertIn == -1)
368 Quit ("Unable to create incoming divert socket.");
369
370 divertOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
371 if (divertOut == -1)
372 Quit ("Unable to create outgoing divert socket.");
373
374 divertInOut = -1;
375
376/*
377 * Bind divert sockets.
378 */
379
380 addr.sin_family = AF_INET;
381 addr.sin_addr.s_addr = INADDR_ANY;
382 addr.sin_port = inPort;
383
384 if (bind (divertIn,
385 (struct sockaddr*) &addr,
386 sizeof addr) == -1)
387 Quit ("Unable to bind incoming divert socket.");
388
389 addr.sin_family = AF_INET;
390 addr.sin_addr.s_addr = INADDR_ANY;
391 addr.sin_port = outPort;
392
393 if (bind (divertOut,
394 (struct sockaddr*) &addr,
395 sizeof addr) == -1)
396 Quit ("Unable to bind outgoing divert socket.");
397 }
398/*
7ba0088d 399 * Create routing socket if interface name specified and in dynamic mode.
b7080c8e 400 */
7ba0088d
A
401 routeSock = -1;
402 if (ifName) {
403 if (dynamicMode) {
b7080c8e 404
7ba0088d
A
405 routeSock = socket (PF_ROUTE, SOCK_RAW, 0);
406 if (routeSock == -1)
407 Quit ("Unable to create routing info socket.");
408
409 assignAliasAddr = 1;
410 }
2b484d24 411 else{
7ba0088d 412 SetAliasAddressFromIfName (ifName);
2b484d24 413 }
b7080c8e 414 }
b7080c8e
A
415/*
416 * Create socket for sending ICMP messages.
417 */
418 icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
419 if (icmpSock == -1)
420 Quit ("Unable to create ICMP socket.");
421
9c859447
A
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.");
2b484d24
A
427
428#if NATPORTMAP
429 if ( enable_natportmap )
430 {
431 /* create socket to listen for port mapping */
432 portmapSock = socket( AF_INET, SOCK_DGRAM, 0);
433 if ( portmapSock != -1 )
434 {
2b484d24
A
435 addr.sin_family = AF_INET;
436 addr.sin_addr.s_addr = INADDR_ANY;
9c859447 437 addr.sin_port = htons(NATPMP_PORT);
2b484d24
A
438
439 if (bind ( portmapSock,
440 (struct sockaddr*) &addr,
441 sizeof addr) == -1)
442 printf("Binding to NATPM port failed!\n");
443
444 /* NATPORTMAPP initial set up */
445 NatPortMapPInit();
446 }
447 if ( !Natdtimerset ){
448 Natdtimerset = 1;
449 signal(SIGALRM, Natdtimer);
450 }
451 }
9c859447
A
452#endif /* NATPORTMAP */
453
b7080c8e
A
454/*
455 * Become a daemon unless verbose mode was requested.
456 */
457 if (!verbose)
458 DaemonMode ();
459/*
460 * Catch signals to manage shutdown and
461 * refresh of interface address.
462 */
7ba0088d
A
463 siginterrupt(SIGTERM, 1);
464 siginterrupt(SIGHUP, 1);
b7080c8e
A
465 signal (SIGTERM, InitiateShutdown);
466 signal (SIGHUP, RefreshAddr);
f47db663 467 signal (SIGINFO, HandleInfo);
b7080c8e
A
468/*
469 * Set alias address if it has been given.
470 */
471 if (aliasAddr.s_addr != INADDR_NONE)
2b484d24 472 {
b7080c8e 473 PacketAliasSetAddress (aliasAddr);
2b484d24
A
474#ifdef NATPORTMAP
475 if ( (enable_natportmap) && (aliasAddr.s_addr != lastassignaliasAddr.s_addr) ){
476 lastassignaliasAddr.s_addr = aliasAddr.s_addr;
477 NotifyPublicAddress();
478 }
479#endif
480 }
b7080c8e
A
481/*
482 * We need largest descriptor number for select.
483 */
484
485 fdMax = -1;
486
487 if (divertIn > fdMax)
488 fdMax = divertIn;
489
490 if (divertOut > fdMax)
491 fdMax = divertOut;
492
493 if (divertInOut > fdMax)
494 fdMax = divertInOut;
495
496 if (routeSock > fdMax)
497 fdMax = routeSock;
498
9c859447
A
499 if (icmpSock > fdMax)
500 fdMax = icmpSock;
501
2b484d24
A
502#ifdef NATPORTMAP
503 if ( portmapSock > fdMax )
504 fdMax = portmapSock;
505
506#endif
507
b7080c8e
A
508 while (running) {
509
510 if (divertInOut != -1 && !ifName && packetSock == -1) {
511/*
512 * When using only one socket, just call
513 * DoAliasing repeatedly to process packets.
514 */
515 DoAliasing (divertInOut, DONT_KNOW);
516 continue;
517 }
518/*
519 * Build read mask from socket descriptors to select.
520 */
521 FD_ZERO (&readMask);
522 FD_ZERO (&writeMask);
523
524/*
525 * If there is unsent packet in buffer, use select
526 * to check when socket comes writable again.
527 */
528 if (packetSock != -1) {
529
530 FD_SET (packetSock, &writeMask);
531 }
532 else {
533/*
534 * No unsent packet exists - safe to check if
535 * new ones are available.
536 */
537 if (divertIn != -1)
538 FD_SET (divertIn, &readMask);
539
540 if (divertOut != -1)
541 FD_SET (divertOut, &readMask);
542
543 if (divertInOut != -1)
544 FD_SET (divertInOut, &readMask);
9c859447
A
545
546 if (icmpSock != -1)
547 FD_SET(icmpSock, &readMask);
b7080c8e
A
548 }
549/*
550 * Routing info is processed always.
551 */
552 if (routeSock != -1)
553 FD_SET (routeSock, &readMask);
2b484d24
A
554#ifdef NATPORTMAP
555 if ( portmapSock != -1 )
556 FD_SET (portmapSock, &readMask);
557#endif
b7080c8e
A
558 if (select (fdMax + 1,
559 &readMask,
560 &writeMask,
561 NULL,
562 NULL) == -1) {
563
f47db663
A
564 if (errno == EINTR) {
565 if (dumpinfo) {
566 DumpInfo();
567 dumpinfo = 0;
568 }
b7080c8e 569 continue;
f47db663 570 }
b7080c8e
A
571 Quit ("Select failed.");
572 }
573
574 if (packetSock != -1)
575 if (FD_ISSET (packetSock, &writeMask))
576 FlushPacketBuffer (packetSock);
577
578 if (divertIn != -1)
579 if (FD_ISSET (divertIn, &readMask))
580 DoAliasing (divertIn, INPUT);
581
582 if (divertOut != -1)
583 if (FD_ISSET (divertOut, &readMask))
584 DoAliasing (divertOut, OUTPUT);
585
586 if (divertInOut != -1)
587 if (FD_ISSET (divertInOut, &readMask))
588 DoAliasing (divertInOut, DONT_KNOW);
589
590 if (routeSock != -1)
591 if (FD_ISSET (routeSock, &readMask))
592 HandleRoutingInfo (routeSock);
9c859447
A
593
594 if (icmpSock != -1)
595 if (FD_ISSET (icmpSock, &readMask))
596 DiscardIncomingPackets (icmpSock);
597
2b484d24
A
598#ifdef NATPORTMAP
599 if ( portmapSock != -1)
600 if (FD_ISSET (portmapSock, &readMask))
601 HandlePortMap( portmapSock );
602#endif
b7080c8e
A
603 }
604
605 if (background)
606 unlink (PIDFILE);
607
608 return 0;
609}
610
611static void DaemonMode ()
612{
613 FILE* pidFile;
614
615 daemon (0, 0);
616 background = 1;
617
618 pidFile = fopen (PIDFILE, "w");
619 if (pidFile) {
620
621 fprintf (pidFile, "%d\n", getpid ());
622 fclose (pidFile);
623 }
9c859447
A
624
625#ifdef DEBUG
626#include <fcntl.h>
627 {
628 int fd;
629
630 fd = open("/var/run/natd.log", O_WRONLY|O_CREAT|O_TRUNC, 0644);
631 if (fd >= 0) {
632 if (fd != STDOUT_FILENO) {
633 dup2(fd, STDOUT_FILENO);
634 close(fd);
635 }
636 dup2(STDOUT_FILENO, STDERR_FILENO);
637 }
638 }
639#endif
b7080c8e
A
640}
641
642static void ParseArgs (int argc, char** argv)
643{
644 int arg;
b7080c8e
A
645 char* opt;
646 char parmBuf[256];
7ba0088d 647 int len; /* bounds checking */
b7080c8e
A
648
649 for (arg = 1; arg < argc; arg++) {
650
651 opt = argv[arg];
652 if (*opt != '-') {
653
654 warnx ("invalid option %s", opt);
655 Usage ();
656 }
657
b7080c8e 658 parmBuf[0] = '\0';
7ba0088d 659 len = 0;
b7080c8e
A
660
661 while (arg < argc - 1) {
662
663 if (argv[arg + 1][0] == '-')
664 break;
665
7ba0088d
A
666 if (len) {
667 strncat (parmBuf, " ", sizeof(parmBuf) - (len + 1));
668 len += strlen(parmBuf + len);
669 }
b7080c8e
A
670
671 ++arg;
7ba0088d
A
672 strncat (parmBuf, argv[arg], sizeof(parmBuf) - (len + 1));
673 len += strlen(parmBuf + len);
674
b7080c8e
A
675 }
676
7ba0088d
A
677 ParseOption (opt + 1, (len ? parmBuf : NULL));
678
b7080c8e
A
679 }
680}
681
682static void DoAliasing (int fd, int direction)
683{
684 int bytes;
685 int origBytes;
686 int status;
f47db663
A
687 socklen_t addrSize;
688 struct ip* ip;
b7080c8e
A
689
690 if (assignAliasAddr) {
691
692 SetAliasAddressFromIfName (ifName);
693 assignAliasAddr = 0;
694 }
695/*
696 * Get packet from socket.
697 */
698 addrSize = sizeof packetAddr;
699 origBytes = recvfrom (fd,
700 packetBuf,
701 sizeof packetBuf,
702 0,
703 (struct sockaddr*) &packetAddr,
704 &addrSize);
705
706 if (origBytes == -1) {
707
708 if (errno != EINTR)
709 Warn ("read from divert socket failed");
710
711 return;
712 }
713/*
714 * This is a IP packet.
715 */
716 ip = (struct ip*) packetBuf;
7ba0088d 717 if (direction == DONT_KNOW) {
b7080c8e
A
718 if (packetAddr.sin_addr.s_addr == INADDR_ANY)
719 direction = OUTPUT;
720 else
721 direction = INPUT;
7ba0088d 722 }
b7080c8e
A
723
724 if (verbose) {
b7080c8e
A
725/*
726 * Print packet direction and protocol type.
727 */
728 printf (direction == OUTPUT ? "Out " : "In ");
729
730 switch (ip->ip_p) {
731 case IPPROTO_TCP:
732 printf ("[TCP] ");
733 break;
734
735 case IPPROTO_UDP:
736 printf ("[UDP] ");
737 break;
738
739 case IPPROTO_ICMP:
740 printf ("[ICMP] ");
741 break;
742
743 default:
744 printf ("[%d] ", ip->ip_p);
745 break;
746 }
747/*
748 * Print addresses.
749 */
750 PrintPacket (ip);
751 }
752
753 if (direction == OUTPUT) {
754/*
755 * Outgoing packets. Do aliasing.
756 */
757 PacketAliasOut (packetBuf, IP_MAXPACKET);
758 }
759 else {
760
761/*
762 * Do aliasing.
763 */
764 status = PacketAliasIn (packetBuf, IP_MAXPACKET);
765 if (status == PKT_ALIAS_IGNORED &&
766 dropIgnoredIncoming) {
767
768 if (verbose)
769 printf (" dropped.\n");
770
771 if (logDropped)
772 SyslogPacket (ip, LOG_WARNING, "denied");
773
774 return;
775 }
776 }
777/*
778 * Length might have changed during aliasing.
779 */
780 bytes = ntohs (ip->ip_len);
781/*
782 * Update alias overhead size for outgoing packets.
783 */
784 if (direction == OUTPUT &&
785 bytes - origBytes > aliasOverhead)
786 aliasOverhead = bytes - origBytes;
787
788 if (verbose) {
789
790/*
791 * Print addresses after aliasing.
792 */
793 printf (" aliased to\n");
794 printf (" ");
795 PrintPacket (ip);
796 printf ("\n");
797 }
798
799 packetLen = bytes;
800 packetSock = fd;
801 packetDirection = direction;
802
803 FlushPacketBuffer (fd);
804}
805
806static void FlushPacketBuffer (int fd)
807{
808 int wrote;
809 char msgBuf[80];
810/*
811 * Put packet back for processing.
812 */
813 wrote = sendto (fd,
814 packetBuf,
815 packetLen,
816 0,
817 (struct sockaddr*) &packetAddr,
818 sizeof packetAddr);
819
820 if (wrote != packetLen) {
821/*
822 * If buffer space is not available,
823 * just return. Main loop will take care of
824 * retrying send when space becomes available.
825 */
826 if (errno == ENOBUFS)
827 return;
828
829 if (errno == EMSGSIZE) {
830
831 if (packetDirection == OUTPUT &&
832 ifMTU != -1)
833 SendNeedFragIcmp (icmpSock,
834 (struct ip*) packetBuf,
835 ifMTU - aliasOverhead);
836 }
837 else {
838
fdfd5971 839 snprintf (msgBuf, sizeof(msgBuf), "failed to write packet back");
b7080c8e
A
840 Warn (msgBuf);
841 }
842 }
843
844 packetSock = -1;
845}
846
847static void HandleRoutingInfo (int fd)
848{
849 int bytes;
850 struct if_msghdr ifMsg;
851/*
852 * Get packet from socket.
853 */
854 bytes = read (fd, &ifMsg, sizeof ifMsg);
855 if (bytes == -1) {
856
857 Warn ("read from routing socket failed");
858 return;
859 }
860
861 if (ifMsg.ifm_version != RTM_VERSION) {
862
863 Warn ("unexpected packet read from routing socket");
864 return;
865 }
866
867 if (verbose)
7ba0088d 868 printf ("Routing message %#x received.\n", ifMsg.ifm_type);
b7080c8e 869
7ba0088d
A
870 if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO) &&
871 ifMsg.ifm_index == ifIndex) {
872 if (verbose)
873 printf("Interface address/MTU has probably changed.\n");
b7080c8e 874 assignAliasAddr = 1;
7ba0088d 875 }
b7080c8e
A
876}
877
9c859447
A
878static void DiscardIncomingPackets (int fd)
879{
880 struct sockaddr_in sin;
881 char buffer[80];
882 socklen_t slen = sizeof(sin);
883
884 while (recvfrom(fd, buffer, sizeof(buffer), 0, (struct sockaddr *)&sin, &slen) != -1) {
885 ;
886 }
887}
888
2b484d24
A
889#ifdef NATPORTMAP
890
891void getdivisor()
892{
893 struct mach_timebase_info info;
894
895 (void) mach_timebase_info (&info);
896
897 secdivisor = ( (double)info.denom / (double)info.numer) * 1000;
898
899}
900
9c859447 901uint32_t getuptime()
2b484d24
A
902{
903 uint64_t now;
9c859447 904 uint32_t epochtime;
2b484d24 905
9c859447
A
906 now = mach_absolute_time();
907 epochtime = (now / secdivisor) / USEC_PER_SEC;
908 return ( epochtime );
2b484d24 909
2b484d24
A
910}
911
912/* set up neccessary info for doing NatPortMapP */
913static void NatPortMapPInit()
914{
915 int i;
916 struct ifaddrs *ifap, *ifa;
917
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 */
9c859447
A
923
924 if (getifaddrs(&ifap) == -1)
925 Quit ("getifaddrs failed.");
926
2b484d24
A
927 for ( ifa= ifap; ifa; ifa=ifa->ifa_next)
928 {
929 struct sockaddr_in * a;
930 if (ifa->ifa_addr->sa_family != AF_INET)
931 {
932 continue;
933 }
934 a = (struct sockaddr_in *)ifa->ifa_addr;
935 for ( i = 0; i < numofinterfaces; i++ )
936 {
937 if (strcmp(ifa->ifa_name, forwardedinterfacename[i]))
938 {
939 continue;
940 }
941 if (forwardedinterfaceaddr[i].s_addr == 0)
942 {
943 /* copy the first IP address */
944 forwardedinterfaceaddr[i] = a->sin_addr;
945 }
946 break;
947 }
948 }
949 freeifaddrs( ifap );
950 getdivisor();
951}
952
953/* SendPortMapResponse */
954/* send generic reponses to NATPORTMAP requests */
955static void SendPortMapResponse( int fd, struct sockaddr_in *clientaddr, int clientaddrlen, unsigned char origopcode, unsigned short result)
956{
957 stderrreply reply;
958 int bytes;
959
960 reply.version = NATPMVERSION;
961 reply.opcode = origopcode + SERVERREPLYOP;
9c859447
A
962 reply.result = htons(result);
963 reply.epoch = htonl(getuptime());
2b484d24
A
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 );
967}
968
969/* SendPublicAddress */
970/* return public address to requestor */
971static void SendPublicAddress( int fd, struct sockaddr_in *clientaddr, int clientaddrlen )
972{
973
974 publicaddrreply reply;
975 int bytes;
976
977 reply.version = NATPMVERSION;
978 reply.opcode = SERVERREPLYOP + PUBLICADDRREQ;
979 reply.result = SUCCESS;
980 reply.addr = lastassignaliasAddr;
9c859447 981 reply.epoch = htonl(getuptime());
2b484d24
A
982
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 );
986}
987
988/* SendPublicPortResponse */
989/* response for portmap request and portmap removal request */
990/* publicport <= 0 means error */
f47db663 991static void SendPublicPortResponse( int fd, struct sockaddr_in *clientaddr, int clientaddrlen, publicportreq *req, u_short publicport, int result)
2b484d24
A
992{
993
994 int bytes;
44d75bbf 995 publicportreply reply;
2b484d24 996
f47db663 997 bzero(&reply, sizeof(publicportreply));
44d75bbf
A
998 reply.version = NATPMVERSION;
999 reply.opcode = SERVERREPLYOP + req->opcode;
f47db663 1000 if (result)
2b484d24 1001 /* error in port mapping */
9c859447 1002 reply.result = htons(OUTOFRESOURCES);
2b484d24 1003 else
44d75bbf 1004 reply.result = SUCCESS;
f47db663 1005
9c859447 1006 reply.epoch = htonl(getuptime());
f47db663
A
1007
1008 reply.privateport = req->privateport;
44d75bbf 1009
f47db663
A
1010 /* adding or renewing a mapping */
1011 if ( req->lifetime ) {
44d75bbf 1012 reply.publicport = publicport;
f47db663 1013 reply.lifetime = req->lifetime;
44d75bbf
A
1014 }
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 );
2b484d24
A
1018}
1019
1020/* SendPortMapMulti */
1021/* send multicast to local network for new alias address */
1022static void SendPortMapMulti()
1023{
1024
1025 publicaddrreply reply;
1026 int bytes;
1027 struct sockaddr_in multiaddr;
1028 int multisock;
1029 int i;
1030
1031#define LOCALGROUP "224.0.0.1"
1032 numoftries++;
1033 memset(&multiaddr,0,sizeof(struct sockaddr_in));
1034 multiaddr.sin_family=AF_INET;
1035 multiaddr.sin_addr.s_addr=inet_addr(LOCALGROUP);
9c859447 1036 multiaddr.sin_port=htons(NATPMP_ANNOUNCEMENT_PORT);
2b484d24
A
1037 reply.version = NATPMVERSION;
1038 reply.opcode = SERVERREPLYOP + PUBLICADDRREQ;
1039 reply.result = SUCCESS;
1040 reply.addr = lastassignaliasAddr;
1041 reply.epoch = 0;
1042
1043 /* send multicast to all forwarded interfaces */
1044 for ( i = 0; i < numofinterfaces; i++)
1045 {
1046 if (forwardedinterfaceaddr[i].s_addr == 0)
1047 {
1048 continue;
1049 }
1050 multisock = socket( AF_INET, SOCK_DGRAM, 0);
1051
1052 if ( multisock == -1 )
1053 {
1054 printf("cannot get socket for sending multicast\n");
1055 return;
1056 }
1057 if (setsockopt(multisock, IPPROTO_IP, IP_MULTICAST_IF, &forwardedinterfaceaddr[i], sizeof(struct in_addr)) < 0)
1058 {
1059 printf("setsockopt failed\n");
1060 close(multisock);
1061 continue;
1062 }
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 );
1066 close(multisock);
1067 }
1068
1069}
1070
1071/* double the time value */
1072static void Doubletime( struct timeval *tvp)
1073{
f47db663
A
1074
1075 timeradd(tvp, tvp, tvp);
1076
2b484d24
A
1077}
1078
1079/* stop running natd timer */
1080static void Stoptimer()
1081{
f47db663
A
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);
2b484d24
A
1086}
1087
1088/* natdtimer */
1089/* timer routine to send new public IP address */
1090static void Natdtimer()
1091{
1092 if ( !enable_natportmap )
1093 return;
1094
1095 SendPortMapMulti();
1096
1097 if ( numoftries < MAXRETRY ){
1098 Doubletime( &itval.it_value);
f47db663
A
1099 itval.it_interval.tv_sec = 0;
1100 itval.it_interval.tv_usec = 0;
2b484d24
A
1101 if (setitimer(ITIMER_REAL, &itval, (struct itimerval *)NULL) < 0)
1102 printf( "setitimer err: %d\n", errno);
1103 }
1104 else
1105 {
1106 Stoptimer();
1107 return;
1108 }
1109
1110}
1111
1112/* NotifyPublicAddress */
1113/* Advertise new public address */
1114static void NotifyPublicAddress()
1115{
1116 if ( numoftries < MAXRETRY)
1117 {
1118 /* there is an old timer running, cancel it */
1119 Stoptimer();
1120 }
1121 /* send up new timer */
1122 numoftries = 0;
1123 SendPortMapMulti();
1124 itval.it_value.tv_sec = 0;
1125 itval.it_value.tv_usec = TIMER_RATE;
1126 itval.it_interval.tv_sec = 0;
f47db663 1127 itval.it_interval.tv_usec = 0;
2b484d24
A
1128 if (setitimer(ITIMER_REAL, &itval, (struct itimerval *)NULL) < 0)
1129 printf( "setitimer err: %d\n", errno);
1130
1131}
1132
1133/* DoPortMapping */
1134/* find/add/remove port mapping from alias manager */
1135void DoPortMapping( int fd, struct sockaddr_in *clientaddr, int clientaddrlen, publicportreq *req)
1136{
1137 u_char proto = IPPROTO_TCP;
1138 int aliasport;
f47db663 1139 struct in_addr inany = { INADDR_ANY };
2b484d24
A
1140
1141 if ( req->opcode == MAPUDPREQ)
1142 proto = IPPROTO_UDP;
1143 if ( req->lifetime == 0)
1144 {
1145 /* remove port mapping */
9c859447
A
1146 if ( !FindAliasPortOut( clientaddr->sin_addr,
1147 inany,
1148 req->privateport,
1149 req->publicport,
1150 proto,
1151 ntohl(req->lifetime),
1152 0) )
2b484d24 1153 /* FindAliasPortOut returns no error, port successfully removed, return no error response to client */
f47db663 1154 SendPublicPortResponse( fd, clientaddr, clientaddrlen, req, 0, 0 );
2b484d24
A
1155 else
1156 /* deleting port fails, return error */
f47db663 1157 SendPublicPortResponse( fd, clientaddr, clientaddrlen, req, 0, -1 );
2b484d24
A
1158 }
1159 else
1160 {
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 */
9c859447
A
1163 aliasport = FindAliasPortOut( clientaddr->sin_addr,
1164 inany, /* lastassignaliasAddr */
1165 req->privateport,
1166 0,
1167 proto,
1168 ntohl(req->lifetime),
1169 1);
2b484d24 1170 /* aliasport should be non zero if mapping is successfully, else -1 is returned, alias port shouldn't be zero???? */
f47db663 1171 SendPublicPortResponse( fd, clientaddr, clientaddrlen, req, aliasport, 0 );
2b484d24
A
1172
1173 }
1174}
1175
1176/* HandlePortMap */
1177/* handle all packets sent to NATPORTMAP port */
1178static void HandlePortMap( int fd )
1179{
f47db663
A
1180 #define MAXBUFFERSIZE 100
1181
1182 struct sockaddr_in clientaddr;
1183 socklen_t clientaddrlen;
1184 unsigned char buffer[MAXBUFFERSIZE];
1185 int bytes;
1186 unsigned short result = SUCCESS;
1187 struct stdportmaprequest *req;
1188
1189 clientaddrlen = sizeof( clientaddr );
1190 bytes = recvfrom( fd, buffer, sizeof(buffer), 0, (struct sockaddr*)&clientaddr, &clientaddrlen);
1191 if ( bytes == -1 )
1192 {
1193 printf( "Read NATPM port error\n");
1194 return;
1195 }
9c859447
A
1196 else if ( bytes < sizeof(stdportmaprequest) )
1197 {
1198 /* drop any requests that are too short */
1199 return;
1200 }
1201
f47db663
A
1202 req = (struct stdportmaprequest*)buffer;
1203
1204 #ifdef DEBUG
1205 {
1206 int i;
2b484d24 1207
f47db663
A
1208 printf("HandlePortMap from %s:%u length= %d: ", inet_ntoa(clientaddr.sin_addr), clientaddr.sin_port, bytes);
1209 for ( i = 0; i<bytes; i++)
2b484d24 1210 {
f47db663 1211 printf("%02x", buffer[i]);
2b484d24 1212 }
f47db663
A
1213 printf("\n");
1214 }
1215 #endif
9c859447
A
1216
1217 /* drop any reply packets that we receive on the floor */
1218 if ( req->opcode >= SERVERREPLYOP )
1219 {
1220 return;
1221 }
1222
f47db663
A
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;
1229
1230 if ( result )
1231 {
1232 SendPortMapResponse( fd, &clientaddr, clientaddrlen, req->opcode, result );
1233 return;
1234 }
1235
1236 switch ( req->opcode )
1237 {
1238 case PUBLICADDRREQ:
2b484d24 1239 {
9c859447
A
1240 if ( bytes == sizeof(stdportmaprequest) )
1241 SendPublicAddress(fd, &clientaddr, clientaddrlen);
f47db663 1242 break;
2b484d24 1243 }
f47db663
A
1244
1245 case MAPUDPREQ:
1246 case MAPTCPREQ:
1247 case MAPUDPTCPREQ:
2b484d24 1248 {
9c859447
A
1249 if ( bytes == sizeof(publicportreq) )
1250 DoPortMapping( fd, &clientaddr, clientaddrlen, (publicportreq*)req);
f47db663 1251 break;
2b484d24 1252 }
f47db663
A
1253
1254
1255 default:
1256 SendPortMapResponse( fd, &clientaddr, clientaddrlen, req->opcode, UNSUPPORTEDOPCODE );
1257 }
1258
2b484d24
A
1259}
1260
9c859447 1261#endif /* NATPORTMAP */
2b484d24 1262
b7080c8e
A
1263static void PrintPacket (struct ip* ip)
1264{
1265 printf ("%s", FormatPacket (ip));
1266}
1267
1268static void SyslogPacket (struct ip* ip, int priority, const char *label)
1269{
1270 syslog (priority, "%s %s", label, FormatPacket (ip));
1271}
1272
1273static char* FormatPacket (struct ip* ip)
1274{
1275 static char buf[256];
1276 struct tcphdr* tcphdr;
1277 struct udphdr* udphdr;
1278 struct icmp* icmphdr;
1279 char src[20];
1280 char dst[20];
1281
fdfd5971
A
1282 strlcpy (src, inet_ntoa (ip->ip_src), sizeof(src));
1283 strlcpy (dst, inet_ntoa (ip->ip_dst), sizeof(dst));
b7080c8e
A
1284
1285 switch (ip->ip_p) {
1286 case IPPROTO_TCP:
1287 tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2));
fdfd5971 1288 snprintf (buf, sizeof(buf), "[TCP] %s:%d -> %s:%d",
b7080c8e
A
1289 src,
1290 ntohs (tcphdr->th_sport),
1291 dst,
1292 ntohs (tcphdr->th_dport));
1293 break;
1294
1295 case IPPROTO_UDP:
1296 udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2));
fdfd5971 1297 snprintf (buf, sizeof(buf), "[UDP] %s:%d -> %s:%d",
b7080c8e
A
1298 src,
1299 ntohs (udphdr->uh_sport),
1300 dst,
1301 ntohs (udphdr->uh_dport));
1302 break;
1303
1304 case IPPROTO_ICMP:
1305 icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2));
fdfd5971 1306 snprintf (buf, sizeof(buf), "[ICMP] %s -> %s %u(%u)",
b7080c8e
A
1307 src,
1308 dst,
1309 icmphdr->icmp_type,
1310 icmphdr->icmp_code);
1311 break;
1312
1313 default:
fdfd5971 1314 snprintf (buf, sizeof(buf), "[%d] %s -> %s ", ip->ip_p, src, dst);
b7080c8e
A
1315 break;
1316 }
1317
1318 return buf;
1319}
1320
7ba0088d
A
1321static void
1322SetAliasAddressFromIfName(const char *ifn)
b7080c8e 1323{
7ba0088d
A
1324 size_t needed;
1325 int mib[6];
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;
1331
1332 mib[0] = CTL_NET;
1333 mib[1] = PF_ROUTE;
1334 mib[2] = 0;
1335 mib[3] = AF_INET; /* Only IP addresses please */
1336 mib[4] = NET_RT_IFLIST;
1337 mib[5] = 0; /* ifIndex??? */
b7080c8e
A
1338/*
1339 * Get interface data.
1340 */
7ba0088d
A
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");
1347 lim = buf + needed;
b7080c8e
A
1348/*
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.
1353 */
7ba0088d
A
1354 ifIndex = 0;
1355 next = buf;
1356 while (next < lim) {
1357 ifm = (struct if_msghdr *)next;
1358 next += ifm->ifm_msglen;
1359 if (ifm->ifm_version != RTM_VERSION) {
1360 if (verbose)
1361 warnx("routing message version %d "
1362 "not understood", ifm->ifm_version);
1363 continue;
b7080c8e 1364 }
7ba0088d
A
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;
285dd90c
A
1371 if (clampMSS)
1372 PacketAliasClampMSS(ifMTU - sizeof(struct tcphdr) - sizeof(struct ip));
7ba0088d
A
1373 break;
1374 }
b7080c8e 1375 }
b7080c8e 1376 }
7ba0088d
A
1377 if (!ifIndex)
1378 errx(1, "unknown interface name %s", ifn);
b7080c8e
A
1379/*
1380 * Get interface address.
1381 */
285dd90c 1382 if (aliasAddr.s_addr == INADDR_NONE) {
7ba0088d
A
1383 sin = NULL;
1384 while (next < lim) {
1385 ifam = (struct ifa_msghdr *)next;
1386 next += ifam->ifam_msglen;
1387 if (ifam->ifam_version != RTM_VERSION) {
1388 if (verbose)
1389 warnx("routing message version %d "
1390 "not understood", ifam->ifam_version);
1391 continue;
1392 }
1393 if (ifam->ifam_type != RTM_NEWADDR)
1394 break;
1395 if (ifam->ifam_addrs & RTA_IFA) {
1396 int i;
1397 char *cp = (char *)(ifam + 1);
1398
1399#define ROUNDUP(a) \
9c859447 1400 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t))
7ba0088d
A
1401#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
1402
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;
1408 break;
1409 }
1410 }
1411 }
1412 if (sin == NULL)
1413 errx(1, "%s: cannot get interface address", ifn);
b7080c8e 1414
7ba0088d 1415 PacketAliasSetAddress(sin->sin_addr);
2b484d24
A
1416#ifdef NATPORTMAP
1417 if ( (enable_natportmap) && (sin->sin_addr.s_addr != lastassignaliasAddr.s_addr) )
1418 {
1419 lastassignaliasAddr.s_addr = sin->sin_addr.s_addr;
1420 /* make sure the timer handler was set before setting timer */
1421 if ( !Natdtimerset ){
1422 Natdtimerset = 1;
1423 signal(SIGALRM, Natdtimer);
1424 }
1425 NotifyPublicAddress();
1426 }
1427#endif
7ba0088d
A
1428 syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes",
1429 inet_ntoa(sin->sin_addr), ifMTU);
285dd90c 1430 }
b7080c8e 1431
7ba0088d 1432 free(buf);
b7080c8e
A
1433}
1434
1435void Quit (const char* msg)
1436{
1437 Warn (msg);
1438 exit (1);
1439}
1440
1441void Warn (const char* msg)
1442{
1443 if (background)
1444 syslog (LOG_ALERT, "%s (%m)", msg);
1445 else
7ba0088d 1446 warn ("%s", msg);
b7080c8e
A
1447}
1448
1449static void RefreshAddr (int sig)
1450{
b7080c8e
A
1451 if (ifName)
1452 assignAliasAddr = 1;
1453}
1454
1455static void InitiateShutdown (int sig)
1456{
1457/*
1458 * Start timer to allow kernel gracefully
1459 * shutdown existing connections when system
1460 * is shut down.
1461 */
7ba0088d 1462 siginterrupt(SIGALRM, 1);
b7080c8e
A
1463 signal (SIGALRM, Shutdown);
1464 alarm (10);
1465}
1466
1467static void Shutdown (int sig)
1468{
1469 running = 0;
1470}
1471
f47db663
A
1472static void HandleInfo (int sig)
1473{
1474 dumpinfo++;
1475}
1476
b7080c8e
A
1477/*
1478 * Different options recognized by this program.
1479 */
1480
1481enum Option {
1482
1483 PacketAliasOption,
1484 Verbose,
1485 InPort,
1486 OutPort,
1487 Port,
1488 AliasAddress,
7ba0088d 1489 TargetAddress,
b7080c8e
A
1490 InterfaceName,
1491 RedirectPort,
7ba0088d 1492 RedirectProto,
b7080c8e
A
1493 RedirectAddress,
1494 ConfigFile,
1495 DynamicMode,
285dd90c 1496 ClampMSS,
b7080c8e
A
1497 ProxyRule,
1498 LogDenied,
7ba0088d 1499 LogFacility,
2b484d24
A
1500 PunchFW,
1501#ifdef NATPORTMAP
1502 NATPortMap,
1503 ToInterfaceName
1504#endif
b7080c8e
A
1505};
1506
1507enum Param {
1508
1509 YesNo,
1510 Numeric,
1511 String,
1512 None,
1513 Address,
1514 Service
1515};
1516
1517/*
1518 * Option information structure (used by ParseOption).
1519 */
1520
1521struct OptionInfo {
1522
1523 enum Option type;
1524 int packetAliasOpt;
1525 enum Param parm;
1526 const char* parmDescription;
1527 const char* description;
1528 const char* name;
1529 const char* shortName;
1530};
1531
1532/*
1533 * Table of known options.
1534 */
1535
1536static struct OptionInfo optionTable[] = {
1537
1538 { PacketAliasOption,
1539 PKT_ALIAS_UNREGISTERED_ONLY,
1540 YesNo,
1541 "[yes|no]",
1542 "alias only unregistered addresses",
1543 "unregistered_only",
1544 "u" },
1545
1546 { PacketAliasOption,
1547 PKT_ALIAS_LOG,
1548 YesNo,
1549 "[yes|no]",
1550 "enable logging",
1551 "log",
1552 "l" },
1553
1554 { PacketAliasOption,
1555 PKT_ALIAS_PROXY_ONLY,
1556 YesNo,
1557 "[yes|no]",
1558 "proxy only",
1559 "proxy_only",
1560 NULL },
1561
1562 { PacketAliasOption,
1563 PKT_ALIAS_REVERSE,
1564 YesNo,
1565 "[yes|no]",
1566 "operate in reverse mode",
1567 "reverse",
1568 NULL },
1569
1570 { PacketAliasOption,
1571 PKT_ALIAS_DENY_INCOMING,
1572 YesNo,
1573 "[yes|no]",
1574 "allow incoming connections",
1575 "deny_incoming",
1576 "d" },
1577
1578 { PacketAliasOption,
1579 PKT_ALIAS_USE_SOCKETS,
1580 YesNo,
1581 "[yes|no]",
1582 "use sockets to inhibit port conflict",
1583 "use_sockets",
1584 "s" },
1585
1586 { PacketAliasOption,
1587 PKT_ALIAS_SAME_PORTS,
1588 YesNo,
1589 "[yes|no]",
1590 "try to keep original port numbers for connections",
1591 "same_ports",
1592 "m" },
1593
1594 { Verbose,
1595 0,
1596 YesNo,
1597 "[yes|no]",
1598 "verbose mode, dump packet information",
1599 "verbose",
1600 "v" },
1601
1602 { DynamicMode,
1603 0,
1604 YesNo,
1605 "[yes|no]",
1606 "dynamic mode, automatically detect interface address changes",
1607 "dynamic",
1608 NULL },
1609
285dd90c
A
1610 { ClampMSS,
1611 0,
1612 YesNo,
1613 "[yes|no]",
1614 "enable TCP MSS clamping",
1615 "clamp_mss",
1616 NULL },
1617
b7080c8e
A
1618 { InPort,
1619 0,
1620 Service,
1621 "number|service_name",
1622 "set port for incoming packets",
1623 "in_port",
1624 "i" },
1625
1626 { OutPort,
1627 0,
1628 Service,
1629 "number|service_name",
1630 "set port for outgoing packets",
1631 "out_port",
1632 "o" },
1633
1634 { Port,
1635 0,
1636 Service,
1637 "number|service_name",
1638 "set port (defaults to natd/divert)",
1639 "port",
1640 "p" },
1641
1642 { AliasAddress,
1643 0,
1644 Address,
1645 "x.x.x.x",
1646 "address to use for aliasing",
1647 "alias_address",
1648 "a" },
1649
7ba0088d
A
1650 { TargetAddress,
1651 0,
1652 Address,
1653 "x.x.x.x",
1654 "address to use for incoming sessions",
1655 "target_address",
1656 "t" },
1657
b7080c8e
A
1658 { InterfaceName,
1659 0,
1660 String,
1661 "network_if_name",
1662 "take aliasing address from interface",
1663 "interface",
1664 "n" },
1665
1666 { ProxyRule,
1667 0,
1668 String,
1669 "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
1670 "a.b.c.d:yyyy",
1671 "add transparent proxying / destination NAT",
1672 "proxy_rule",
1673 NULL },
1674
1675 { RedirectPort,
1676 0,
1677 String,
7ba0088d 1678 "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
b7080c8e
A
1679 " [remote_addr[:remote_port_range]]",
1680 "redirect a port (or ports) for incoming traffic",
1681 "redirect_port",
1682 NULL },
1683
7ba0088d 1684 { RedirectProto,
b7080c8e
A
1685 0,
1686 String,
7ba0088d
A
1687 "proto local_addr [public_addr] [remote_addr]",
1688 "redirect packets of a given proto",
1689 "redirect_proto",
b7080c8e
A
1690 NULL },
1691
7ba0088d 1692 { RedirectAddress,
b7080c8e
A
1693 0,
1694 String,
7ba0088d
A
1695 "local_addr[,...] public_addr",
1696 "define mapping between local and public addresses",
1697 "redirect_address",
b7080c8e
A
1698 NULL },
1699
1700 { ConfigFile,
1701 0,
1702 String,
1703 "file_name",
1704 "read options from configuration file",
1705 "config",
1706 "f" },
1707
1708 { LogDenied,
1709 0,
1710 YesNo,
1711 "[yes|no]",
1712 "enable logging of denied incoming packets",
1713 "log_denied",
1714 NULL },
1715
1716 { LogFacility,
1717 0,
1718 String,
1719 "facility",
1720 "name of syslog facility to use for logging",
1721 "log_facility",
7ba0088d 1722 NULL },
b7080c8e 1723
7ba0088d
A
1724 { PunchFW,
1725 0,
1726 String,
1727 "basenumber:count",
1728 "punch holes in the firewall for incoming FTP/IRC DCC connections",
1729 "punch_fw",
2b484d24
A
1730 NULL },
1731
1732#ifdef NATPORTMAP
1733 { NATPortMap,
1734 0,
1735 YesNo,
1736 "[yes|no]",
1737 "enable NATPortMap protocol",
1738 "enable_natportmap",
1739 NULL },
1740
1741 { ToInterfaceName,
1742 0,
1743 String,
1744 "network_if_name",
1745 "take aliasing address to interface",
1746 "natportmap_interface",
1747 NULL },
1748
1749#endif
b7080c8e
A
1750};
1751
7ba0088d 1752static void ParseOption (const char* option, const char* parms)
b7080c8e
A
1753{
1754 int i;
1755 struct OptionInfo* info;
1756 int yesNoValue;
1757 int aliasValue;
1758 int numValue;
1759 u_short uNumValue;
1760 const char* strValue;
1761 struct in_addr addrValue;
1762 int max;
1763 char* end;
1764 CODE* fac_record = NULL;
1765/*
1766 * Find option from table.
1767 */
1768 max = sizeof (optionTable) / sizeof (struct OptionInfo);
1769 for (i = 0, info = optionTable; i < max; i++, info++) {
1770
1771 if (!strcmp (info->name, option))
1772 break;
1773
1774 if (info->shortName)
1775 if (!strcmp (info->shortName, option))
1776 break;
1777 }
1778
1779 if (i >= max) {
1780
1781 warnx ("unknown option %s", option);
1782 Usage ();
1783 }
1784
1785 uNumValue = 0;
1786 yesNoValue = 0;
1787 numValue = 0;
1788 strValue = NULL;
1789/*
1790 * Check parameters.
1791 */
1792 switch (info->parm) {
1793 case YesNo:
1794 if (!parms)
1795 parms = "yes";
1796
1797 if (!strcmp (parms, "yes"))
1798 yesNoValue = 1;
1799 else
1800 if (!strcmp (parms, "no"))
1801 yesNoValue = 0;
1802 else
1803 errx (1, "%s needs yes/no parameter", option);
1804 break;
1805
1806 case Service:
1807 if (!parms)
1808 errx (1, "%s needs service name or "
1809 "port number parameter",
1810 option);
1811
1812 uNumValue = StrToPort (parms, "divert");
1813 break;
1814
1815 case Numeric:
1816 if (parms)
1817 numValue = strtol (parms, &end, 10);
1818 else
1819 end = NULL;
1820
1821 if (end == parms)
1822 errx (1, "%s needs numeric parameter", option);
1823 break;
1824
1825 case String:
1826 strValue = parms;
1827 if (!strValue)
1828 errx (1, "%s needs parameter", option);
1829 break;
1830
1831 case None:
1832 if (parms)
1833 errx (1, "%s does not take parameters", option);
1834 break;
1835
1836 case Address:
1837 if (!parms)
1838 errx (1, "%s needs address/host parameter", option);
1839
1840 StrToAddr (parms, &addrValue);
1841 break;
1842 }
1843
1844 switch (info->type) {
1845 case PacketAliasOption:
1846
1847 aliasValue = yesNoValue ? info->packetAliasOpt : 0;
1848 PacketAliasSetMode (aliasValue, info->packetAliasOpt);
1849 break;
1850
1851 case Verbose:
1852 verbose = yesNoValue;
1853 break;
1854
1855 case DynamicMode:
1856 dynamicMode = yesNoValue;
1857 break;
1858
285dd90c
A
1859 case ClampMSS:
1860 clampMSS = yesNoValue;
1861 break;
1862
b7080c8e
A
1863 case InPort:
1864 inPort = uNumValue;
1865 break;
1866
1867 case OutPort:
1868 outPort = uNumValue;
1869 break;
1870
1871 case Port:
1872 inOutPort = uNumValue;
1873 break;
1874
1875 case AliasAddress:
1876 memcpy (&aliasAddr, &addrValue, sizeof (struct in_addr));
1877 break;
1878
7ba0088d
A
1879 case TargetAddress:
1880 PacketAliasSetTarget(addrValue);
1881 break;
1882
b7080c8e
A
1883 case RedirectPort:
1884 SetupPortRedirect (strValue);
1885 break;
1886
7ba0088d
A
1887 case RedirectProto:
1888 SetupProtoRedirect(strValue);
b7080c8e
A
1889 break;
1890
7ba0088d
A
1891 case RedirectAddress:
1892 SetupAddressRedirect (strValue);
b7080c8e
A
1893 break;
1894
1895 case ProxyRule:
1896 PacketAliasProxyRule (strValue);
1897 break;
1898
1899 case InterfaceName:
1900 if (ifName)
1901 free (ifName);
1902
1903 ifName = strdup (strValue);
b7080c8e
A
1904 break;
1905
1906 case ConfigFile:
1907 ReadConfigFile (strValue);
1908 break;
1909
1910 case LogDenied:
1911 logDropped = 1;
1912 break;
1913
1914 case LogFacility:
1915
1916 fac_record = facilitynames;
1917 while (fac_record->c_name != NULL) {
1918
1919 if (!strcmp (fac_record->c_name, strValue)) {
1920
1921 logFacility = fac_record->c_val;
1922 break;
1923
1924 }
1925 else
1926 fac_record++;
1927 }
1928
1929 if(fac_record->c_name == NULL)
1930 errx(1, "Unknown log facility name: %s", strValue);
1931
1932 break;
7ba0088d
A
1933
1934 case PunchFW:
1935 SetupPunchFW(strValue);
1936 break;
2b484d24
A
1937
1938#ifdef NATPORTMAP
1939 case NATPortMap:
1940 enable_natportmap = yesNoValue;
1941 break;
1942
1943
1944 case ToInterfaceName:
1945 {
1946 if (forwardedinterfacename != NULL)
1947 {
a714067a 1948 if ( (forwardedinterfacename = realloc( forwardedinterfacename, (numofinterfaces+1) * sizeof(*forwardedinterfacename ))) == NULL ){
2b484d24
A
1949 printf("realloc error, cannot allocate memory for fowarded interface name.\n");
1950 return;
1951 }
1952 }
1953 else {
1954 if ( (forwardedinterfacename = malloc( sizeof(*forwardedinterfacename) )) == NULL ){
1955 printf("malloc error, cannot allocate memory for fowarded interface name.\n");
1956 return;
1957 }
1958 }
1959
1960 forwardedinterfacename[numofinterfaces] = strdup(strValue);
1961 numofinterfaces++;
1962
1963 break;
1964 }
1965
1966#endif
1967
b7080c8e
A
1968 }
1969}
1970
1971void ReadConfigFile (const char* fileName)
1972{
1973 FILE* file;
7ba0088d
A
1974 char *buf;
1975 size_t len;
1976 char *ptr, *p;
b7080c8e
A
1977 char* option;
1978
1979 file = fopen (fileName, "r");
7ba0088d
A
1980 if (!file)
1981 err(1, "cannot open config file %s", fileName);
b7080c8e 1982
7ba0088d
A
1983 while ((buf = fgetln(file, &len)) != NULL) {
1984 if (buf[len - 1] == '\n')
1985 buf[len - 1] = '\0';
1986 else
1987 errx(1, "config file format error: "
1988 "last line should end with newline");
b7080c8e 1989
b7080c8e 1990/*
7ba0088d 1991 * Check for comments, strip off trailing spaces.
b7080c8e 1992 */
7ba0088d
A
1993 if ((ptr = strchr(buf, '#')))
1994 *ptr = '\0';
1995 for (ptr = buf; isspace(*ptr); ++ptr)
1996 continue;
b7080c8e
A
1997 if (*ptr == '\0')
1998 continue;
7ba0088d
A
1999 for (p = strchr(buf, '\0'); isspace(*--p);)
2000 continue;
2001 *++p = '\0';
2002
b7080c8e
A
2003/*
2004 * Extract option name.
2005 */
2006 option = ptr;
2007 while (*ptr && !isspace (*ptr))
2008 ++ptr;
2009
2010 if (*ptr != '\0') {
2011
2012 *ptr = '\0';
2013 ++ptr;
2014 }
2015/*
2016 * Skip white space between name and parms.
2017 */
2018 while (*ptr && isspace (*ptr))
2019 ++ptr;
2020
7ba0088d 2021 ParseOption (option, *ptr ? ptr : NULL);
b7080c8e
A
2022 }
2023
2024 fclose (file);
2025}
2026
2027static void Usage ()
2028{
2029 int i;
2030 int max;
2031 struct OptionInfo* info;
2032
2033 fprintf (stderr, "Recognized options:\n\n");
2034
2035 max = sizeof (optionTable) / sizeof (struct OptionInfo);
2036 for (i = 0, info = optionTable; i < max; i++, info++) {
2037
2038 fprintf (stderr, "-%-20s %s\n", info->name,
2039 info->parmDescription);
2040
2041 if (info->shortName)
2042 fprintf (stderr, "-%-20s %s\n", info->shortName,
2043 info->parmDescription);
2044
2045 fprintf (stderr, " %s\n\n", info->description);
2046 }
2047
2048 exit (1);
2049}
2050
b7080c8e
A
2051void SetupPortRedirect (const char* parms)
2052{
2053 char buf[128];
2054 char* ptr;
7ba0088d 2055 char* serverPool;
b7080c8e
A
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;
2066 int proto;
2067 char* protoName;
2068 char* separator;
2069 int i;
7ba0088d 2070 struct alias_link *link = NULL;
b7080c8e 2071
fdfd5971 2072 strlcpy (buf, parms, sizeof(buf));
b7080c8e
A
2073/*
2074 * Extract protocol.
2075 */
2076 protoName = strtok (buf, " \t");
2077 if (!protoName)
2078 errx (1, "redirect_port: missing protocol");
2079
2080 proto = StrToProto (protoName);
2081/*
2082 * Extract local address.
2083 */
2084 ptr = strtok (NULL, " \t");
2085 if (!ptr)
2086 errx (1, "redirect_port: missing local address");
2087
7ba0088d
A
2088 separator = strchr(ptr, ',');
2089 if (separator) { /* LSNAT redirection syntax. */
2090 localAddr.s_addr = INADDR_NONE;
2091 localPort = ~0;
2092 numLocalPorts = 1;
2093 serverPool = ptr;
2094 } else {
2095 if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 )
2096 errx (1, "redirect_port: invalid local port range");
2097
2098 localPort = GETLOPORT(portRange);
2099 numLocalPorts = GETNUMPORTS(portRange);
2100 serverPool = NULL;
2101 }
b7080c8e
A
2102
2103/*
7ba0088d 2104 * Extract public port and optionally address.
b7080c8e
A
2105 */
2106 ptr = strtok (NULL, " \t");
2107 if (!ptr)
2108 errx (1, "redirect_port: missing public port");
2109
2110 separator = strchr (ptr, ':');
2111 if (separator) {
2112 if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 )
2113 errx (1, "redirect_port: invalid public port range");
2114 }
2115 else {
2116 publicAddr.s_addr = INADDR_ANY;
2117 if (StrToPortRange (ptr, protoName, &portRange) != 0)
2118 errx (1, "redirect_port: invalid public port range");
2119 }
2120
2121 publicPort = GETLOPORT(portRange);
2122 numPublicPorts = GETNUMPORTS(portRange);
2123
2124/*
2125 * Extract remote address and optionally port.
2126 */
2127 ptr = strtok (NULL, " \t");
2128 if (ptr) {
2129 separator = strchr (ptr, ':');
7ba0088d 2130 if (separator) {
b7080c8e
A
2131 if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0)
2132 errx (1, "redirect_port: invalid remote port range");
7ba0088d 2133 } else {
b7080c8e
A
2134 SETLOPORT(portRange, 0);
2135 SETNUMPORTS(portRange, 1);
2136 StrToAddr (ptr, &remoteAddr);
2137 }
2138 }
2139 else {
2140 SETLOPORT(portRange, 0);
2141 SETNUMPORTS(portRange, 1);
2142 remoteAddr.s_addr = INADDR_ANY;
2143 }
2144
2145 remotePort = GETLOPORT(portRange);
2146 numRemotePorts = GETNUMPORTS(portRange);
2147
2148/*
2149 * Make sure port ranges match up, then add the redirect ports.
2150 */
2151 if (numLocalPorts != numPublicPorts)
2152 errx (1, "redirect_port: port ranges must be equal in size");
2153
2154 /* Remote port range is allowed to be '0' which means all ports. */
7ba0088d 2155 if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0))
b7080c8e
A
2156 errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
2157
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)
2162 remotePortCopy = 0;
2163
7ba0088d
A
2164 link = PacketAliasRedirectPort (localAddr,
2165 htons(localPort + i),
2166 remoteAddr,
2167 htons(remotePortCopy),
2168 publicAddr,
2169 htons(publicPort + i),
2170 proto);
b7080c8e 2171 }
7ba0088d
A
2172
2173/*
2174 * Setup LSNAT server pool.
2175 */
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");
2181
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, ",");
2187 }
2188 }
2189}
2190
2191void
2192SetupProtoRedirect(const char* parms)
2193{
2194 char buf[128];
2195 char* ptr;
2196 struct in_addr localAddr;
2197 struct in_addr publicAddr;
2198 struct in_addr remoteAddr;
2199 int proto;
2200 char* protoName;
2201 struct protoent *protoent;
2202
fdfd5971 2203 strlcpy (buf, parms, sizeof(buf));
7ba0088d
A
2204/*
2205 * Extract protocol.
2206 */
2207 protoName = strtok(buf, " \t");
2208 if (!protoName)
2209 errx(1, "redirect_proto: missing protocol");
2210
2211 protoent = getprotobyname(protoName);
2212 if (protoent == NULL)
2213 errx(1, "redirect_proto: unknown protocol %s", protoName);
2214 else
2215 proto = protoent->p_proto;
2216/*
2217 * Extract local address.
2218 */
2219 ptr = strtok(NULL, " \t");
2220 if (!ptr)
2221 errx(1, "redirect_proto: missing local address");
2222 else
2223 StrToAddr(ptr, &localAddr);
2224/*
2225 * Extract optional public address.
2226 */
2227 ptr = strtok(NULL, " \t");
2228 if (ptr)
2229 StrToAddr(ptr, &publicAddr);
2230 else
2231 publicAddr.s_addr = INADDR_ANY;
2232/*
2233 * Extract optional remote address.
2234 */
2235 ptr = strtok(NULL, " \t");
2236 if (ptr)
2237 StrToAddr(ptr, &remoteAddr);
2238 else
2239 remoteAddr.s_addr = INADDR_ANY;
2240/*
2241 * Create aliasing link.
2242 */
2243 (void)PacketAliasRedirectProto(localAddr, remoteAddr, publicAddr,
2244 proto);
b7080c8e
A
2245}
2246
2247void SetupAddressRedirect (const char* parms)
2248{
2249 char buf[128];
2250 char* ptr;
7ba0088d 2251 char* separator;
b7080c8e
A
2252 struct in_addr localAddr;
2253 struct in_addr publicAddr;
7ba0088d
A
2254 char* serverPool;
2255 struct alias_link *link;
b7080c8e 2256
fdfd5971 2257 strlcpy (buf, parms, sizeof(buf));
b7080c8e
A
2258/*
2259 * Extract local address.
2260 */
2261 ptr = strtok (buf, " \t");
2262 if (!ptr)
2263 errx (1, "redirect_address: missing local address");
2264
7ba0088d
A
2265 separator = strchr(ptr, ',');
2266 if (separator) { /* LSNAT redirection syntax. */
2267 localAddr.s_addr = INADDR_NONE;
2268 serverPool = ptr;
2269 } else {
2270 StrToAddr (ptr, &localAddr);
2271 serverPool = NULL;
2272 }
b7080c8e
A
2273/*
2274 * Extract public address.
2275 */
2276 ptr = strtok (NULL, " \t");
2277 if (!ptr)
2278 errx (1, "redirect_address: missing public address");
2279
2280 StrToAddr (ptr, &publicAddr);
7ba0088d
A
2281 link = PacketAliasRedirectAddr(localAddr, publicAddr);
2282
2283/*
2284 * Setup LSNAT server pool.
2285 */
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, ",");
2292 }
2293 }
b7080c8e
A
2294}
2295
2296void StrToAddr (const char* str, struct in_addr* addr)
2297{
2298 struct hostent* hp;
2299
2300 if (inet_aton (str, addr))
2301 return;
2302
2303 hp = gethostbyname (str);
2304 if (!hp)
2305 errx (1, "unknown host %s", str);
2306
2307 memcpy (addr, hp->h_addr, sizeof (struct in_addr));
2308}
2309
2310u_short StrToPort (const char* str, const char* proto)
2311{
2312 u_short port;
2313 struct servent* sp;
2314 char* end;
2315
2316 port = strtol (str, &end, 10);
2317 if (end != str)
2318 return htons (port);
2319
2320 sp = getservbyname (str, proto);
2321 if (!sp)
2322 errx (1, "unknown service %s/%s", str, proto);
2323
2324 return sp->s_port;
2325}
2326
2327int StrToPortRange (const char* str, const char* proto, port_range *portRange)
2328{
2329 char* sep;
2330 struct servent* sp;
2331 char* end;
2332 u_short loPort;
2333 u_short hiPort;
2334
2335 /* First see if this is a service, return corresponding port if so. */
2336 sp = getservbyname (str,proto);
2337 if (sp) {
2338 SETLOPORT(*portRange, ntohs(sp->s_port));
2339 SETNUMPORTS(*portRange, 1);
2340 return 0;
2341 }
2342
2343 /* Not a service, see if it's a single port or port range. */
2344 sep = strchr (str, '-');
2345 if (sep == NULL) {
2346 SETLOPORT(*portRange, strtol(str, &end, 10));
2347 if (end != str) {
2348 /* Single port. */
2349 SETNUMPORTS(*portRange, 1);
2350 return 0;
2351 }
2352
2353 /* Error in port range field. */
2354 errx (1, "unknown service %s/%s", str, proto);
2355 }
2356
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);
2363
2364 if (GETNUMPORTS(*portRange) == 0)
2365 errx (1, "invalid port range %s", str);
2366
2367 return 0;
2368}
2369
2370
2371int StrToProto (const char* str)
2372{
2373 if (!strcmp (str, "tcp"))
2374 return IPPROTO_TCP;
2375
2376 if (!strcmp (str, "udp"))
2377 return IPPROTO_UDP;
2378
2379 errx (1, "unknown protocol %s. Expected tcp or udp", str);
2380}
2381
2382int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange)
2383{
2384 char* ptr;
2385
2386 ptr = strchr (str, ':');
2387 if (!ptr)
2388 errx (1, "%s is missing port number", str);
2389
2390 *ptr = '\0';
2391 ++ptr;
2392
2393 StrToAddr (str, addr);
2394 return StrToPortRange (ptr, proto, portRange);
2395}
7ba0088d
A
2396
2397static void
2398SetupPunchFW(const char *strValue)
2399{
2400 unsigned int base, num;
2401
2402 if (sscanf(strValue, "%u:%u", &base, &num) != 2)
2403 errx(1, "punch_fw: basenumber:count parameter required");
2404
2405 PacketAliasSetFWBase(base, num);
2406 (void)PacketAliasSetMode(PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);
2407}