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