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