]> git.saurik.com Git - apple/network_cmds.git/blob - natd.tproj/natd.c
network_cmds-176.4.1.tar.gz
[apple/network_cmds.git] / natd.tproj / natd.c
1 /*
2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
11 *
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
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
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 *
33 * Based upon:
34 * $FreeBSD: src/sbin/natd/natd.c,v 1.25.2.3 2000/07/11 20:00:57 ru Exp $
35 */
36
37 #define SYSLOG_NAMES
38
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <sys/sysctl.h>
42 #include <sys/time.h>
43
44 #include <netinet/in.h>
45 #include <netinet/in_systm.h>
46 #include <netinet/ip.h>
47 #include <netinet/tcp.h>
48 #include <netinet/udp.h>
49 #include <netinet/ip_icmp.h>
50 #include <net/if.h>
51 #include <net/if_dl.h>
52 #include <net/route.h>
53 #include <arpa/inet.h>
54
55 #include <alias.h>
56 #include <ctype.h>
57 #include <err.h>
58 #include <errno.h>
59 #include <netdb.h>
60 #include <signal.h>
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <string.h>
64 #include <syslog.h>
65 #include <unistd.h>
66
67 #include "natd.h"
68
69 /*
70 * Default values for input and output
71 * divert socket ports.
72 */
73
74 #define DEFAULT_SERVICE "natd"
75
76 /*
77 * Definition of a port range, and macros to deal with values.
78 * FORMAT: HI 16-bits == first port in range, 0 == all ports.
79 * LO 16-bits == number of ports in range
80 * NOTES: - Port values are not stored in network byte order.
81 */
82
83 typedef u_long port_range;
84
85 #define GETLOPORT(x) ((x) >> 0x10)
86 #define GETNUMPORTS(x) ((x) & 0x0000ffff)
87 #define GETHIPORT(x) (GETLOPORT((x)) + GETNUMPORTS((x)))
88
89 /* Set y to be the low-port value in port_range variable x. */
90 #define SETLOPORT(x,y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
91
92 /* Set y to be the number of ports in port_range variable x. */
93 #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y))
94
95 /*
96 * Function prototypes.
97 */
98
99 static void DoAliasing (int fd, int direction);
100 static void DaemonMode (void);
101 static void HandleRoutingInfo (int fd);
102 static void Usage (void);
103 static char* FormatPacket (struct ip*);
104 static void PrintPacket (struct ip*);
105 static void SyslogPacket (struct ip*, int priority, const char *label);
106 static void SetAliasAddressFromIfName (const char *ifName);
107 static void InitiateShutdown (int);
108 static void Shutdown (int);
109 static void RefreshAddr (int);
110 static void ParseOption (const char* option, const char* parms);
111 static void ReadConfigFile (const char* fileName);
112 static void SetupPortRedirect (const char* parms);
113 static void SetupProtoRedirect(const char* parms);
114 static void SetupAddressRedirect (const char* parms);
115 static void StrToAddr (const char* str, struct in_addr* addr);
116 static u_short StrToPort (const char* str, const char* proto);
117 static int StrToPortRange (const char* str, const char* proto, port_range *portRange);
118 static int StrToProto (const char* str);
119 static int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange);
120 static void ParseArgs (int argc, char** argv);
121 static void FlushPacketBuffer (int fd);
122 static void SetupPunchFW(const char *strValue);
123
124 /*
125 * Globals.
126 */
127
128 static int verbose;
129 static int background;
130 static int running;
131 static int assignAliasAddr;
132 static char* ifName;
133 static int ifIndex;
134 static u_short inPort;
135 static u_short outPort;
136 static u_short inOutPort;
137 static struct in_addr aliasAddr;
138 static int dynamicMode;
139 static int clampMSS;
140 static int ifMTU;
141 static int aliasOverhead;
142 static int icmpSock;
143 static char packetBuf[IP_MAXPACKET];
144 static int packetLen;
145 static struct sockaddr_in packetAddr;
146 static int packetSock;
147 static int packetDirection;
148 static int dropIgnoredIncoming;
149 static int logDropped;
150 static int logFacility;
151
152 int main (int argc, char** argv)
153 {
154 int divertIn;
155 int divertOut;
156 int divertInOut;
157 int routeSock;
158 struct sockaddr_in addr;
159 fd_set readMask;
160 fd_set writeMask;
161 int fdMax;
162 /*
163 * Initialize packet aliasing software.
164 * Done already here to be able to alter option bits
165 * during command line and configuration file processing.
166 */
167 PacketAliasInit ();
168 /*
169 * Parse options.
170 */
171 inPort = 0;
172 outPort = 0;
173 verbose = 0;
174 inOutPort = 0;
175 ifName = NULL;
176 ifMTU = -1;
177 background = 0;
178 running = 1;
179 assignAliasAddr = 0;
180 aliasAddr.s_addr = INADDR_NONE;
181 aliasOverhead = 12;
182 dynamicMode = 0;
183 logDropped = 0;
184 logFacility = LOG_DAEMON;
185 /*
186 * Mark packet buffer empty.
187 */
188 packetSock = -1;
189 packetDirection = DONT_KNOW;
190
191 ParseArgs (argc, argv);
192 /*
193 * Open syslog channel.
194 */
195 openlog ("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0),
196 logFacility);
197 /*
198 * Check that valid aliasing address has been given.
199 */
200 if (aliasAddr.s_addr == INADDR_NONE && ifName == NULL)
201 errx (1, "aliasing address not given");
202
203 /*
204 * Check that valid port number is known.
205 */
206 if (inPort != 0 || outPort != 0)
207 if (inPort == 0 || outPort == 0)
208 errx (1, "both input and output ports are required");
209
210 if (inPort == 0 && outPort == 0 && inOutPort == 0)
211 ParseOption ("port", DEFAULT_SERVICE);
212
213 /*
214 * Check if ignored packets should be dropped.
215 */
216 dropIgnoredIncoming = PacketAliasSetMode (0, 0);
217 dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING;
218 /*
219 * Create divert sockets. Use only one socket if -p was specified
220 * on command line. Otherwise, create separate sockets for
221 * outgoing and incoming connnections.
222 */
223 if (inOutPort) {
224
225 divertInOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
226 if (divertInOut == -1)
227 Quit ("Unable to create divert socket.");
228
229 divertIn = -1;
230 divertOut = -1;
231 /*
232 * Bind socket.
233 */
234
235 addr.sin_family = AF_INET;
236 addr.sin_addr.s_addr = INADDR_ANY;
237 addr.sin_port = inOutPort;
238
239 if (bind (divertInOut,
240 (struct sockaddr*) &addr,
241 sizeof addr) == -1)
242 Quit ("Unable to bind divert socket.");
243 }
244 else {
245
246 divertIn = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
247 if (divertIn == -1)
248 Quit ("Unable to create incoming divert socket.");
249
250 divertOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
251 if (divertOut == -1)
252 Quit ("Unable to create outgoing divert socket.");
253
254 divertInOut = -1;
255
256 /*
257 * Bind divert sockets.
258 */
259
260 addr.sin_family = AF_INET;
261 addr.sin_addr.s_addr = INADDR_ANY;
262 addr.sin_port = inPort;
263
264 if (bind (divertIn,
265 (struct sockaddr*) &addr,
266 sizeof addr) == -1)
267 Quit ("Unable to bind incoming divert socket.");
268
269 addr.sin_family = AF_INET;
270 addr.sin_addr.s_addr = INADDR_ANY;
271 addr.sin_port = outPort;
272
273 if (bind (divertOut,
274 (struct sockaddr*) &addr,
275 sizeof addr) == -1)
276 Quit ("Unable to bind outgoing divert socket.");
277 }
278 /*
279 * Create routing socket if interface name specified and in dynamic mode.
280 */
281 routeSock = -1;
282 if (ifName) {
283 if (dynamicMode) {
284
285 routeSock = socket (PF_ROUTE, SOCK_RAW, 0);
286 if (routeSock == -1)
287 Quit ("Unable to create routing info socket.");
288
289 assignAliasAddr = 1;
290 }
291 else
292 SetAliasAddressFromIfName (ifName);
293 }
294 /*
295 * Create socket for sending ICMP messages.
296 */
297 icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
298 if (icmpSock == -1)
299 Quit ("Unable to create ICMP socket.");
300
301 /*
302 * And disable reads for the socket, otherwise it slowly fills
303 * up with received icmps which we do not use.
304 */
305 shutdown(icmpSock, SHUT_RD);
306
307 /*
308 * Become a daemon unless verbose mode was requested.
309 */
310 if (!verbose)
311 DaemonMode ();
312 /*
313 * Catch signals to manage shutdown and
314 * refresh of interface address.
315 */
316 siginterrupt(SIGTERM, 1);
317 siginterrupt(SIGHUP, 1);
318 signal (SIGTERM, InitiateShutdown);
319 signal (SIGHUP, RefreshAddr);
320 /*
321 * Set alias address if it has been given.
322 */
323 if (aliasAddr.s_addr != INADDR_NONE)
324 PacketAliasSetAddress (aliasAddr);
325 /*
326 * We need largest descriptor number for select.
327 */
328
329 fdMax = -1;
330
331 if (divertIn > fdMax)
332 fdMax = divertIn;
333
334 if (divertOut > fdMax)
335 fdMax = divertOut;
336
337 if (divertInOut > fdMax)
338 fdMax = divertInOut;
339
340 if (routeSock > fdMax)
341 fdMax = routeSock;
342
343 while (running) {
344
345 if (divertInOut != -1 && !ifName && packetSock == -1) {
346 /*
347 * When using only one socket, just call
348 * DoAliasing repeatedly to process packets.
349 */
350 DoAliasing (divertInOut, DONT_KNOW);
351 continue;
352 }
353 /*
354 * Build read mask from socket descriptors to select.
355 */
356 FD_ZERO (&readMask);
357 FD_ZERO (&writeMask);
358
359 /*
360 * If there is unsent packet in buffer, use select
361 * to check when socket comes writable again.
362 */
363 if (packetSock != -1) {
364
365 FD_SET (packetSock, &writeMask);
366 }
367 else {
368 /*
369 * No unsent packet exists - safe to check if
370 * new ones are available.
371 */
372 if (divertIn != -1)
373 FD_SET (divertIn, &readMask);
374
375 if (divertOut != -1)
376 FD_SET (divertOut, &readMask);
377
378 if (divertInOut != -1)
379 FD_SET (divertInOut, &readMask);
380 }
381 /*
382 * Routing info is processed always.
383 */
384 if (routeSock != -1)
385 FD_SET (routeSock, &readMask);
386
387 if (select (fdMax + 1,
388 &readMask,
389 &writeMask,
390 NULL,
391 NULL) == -1) {
392
393 if (errno == EINTR)
394 continue;
395
396 Quit ("Select failed.");
397 }
398
399 if (packetSock != -1)
400 if (FD_ISSET (packetSock, &writeMask))
401 FlushPacketBuffer (packetSock);
402
403 if (divertIn != -1)
404 if (FD_ISSET (divertIn, &readMask))
405 DoAliasing (divertIn, INPUT);
406
407 if (divertOut != -1)
408 if (FD_ISSET (divertOut, &readMask))
409 DoAliasing (divertOut, OUTPUT);
410
411 if (divertInOut != -1)
412 if (FD_ISSET (divertInOut, &readMask))
413 DoAliasing (divertInOut, DONT_KNOW);
414
415 if (routeSock != -1)
416 if (FD_ISSET (routeSock, &readMask))
417 HandleRoutingInfo (routeSock);
418 }
419
420 if (background)
421 unlink (PIDFILE);
422
423 return 0;
424 }
425
426 static void DaemonMode ()
427 {
428 FILE* pidFile;
429
430 daemon (0, 0);
431 background = 1;
432
433 pidFile = fopen (PIDFILE, "w");
434 if (pidFile) {
435
436 fprintf (pidFile, "%d\n", getpid ());
437 fclose (pidFile);
438 }
439 }
440
441 static void ParseArgs (int argc, char** argv)
442 {
443 int arg;
444 char* opt;
445 char parmBuf[256];
446 int len; /* bounds checking */
447
448 for (arg = 1; arg < argc; arg++) {
449
450 opt = argv[arg];
451 if (*opt != '-') {
452
453 warnx ("invalid option %s", opt);
454 Usage ();
455 }
456
457 parmBuf[0] = '\0';
458 len = 0;
459
460 while (arg < argc - 1) {
461
462 if (argv[arg + 1][0] == '-')
463 break;
464
465 if (len) {
466 strncat (parmBuf, " ", sizeof(parmBuf) - (len + 1));
467 len += strlen(parmBuf + len);
468 }
469
470 ++arg;
471 strncat (parmBuf, argv[arg], sizeof(parmBuf) - (len + 1));
472 len += strlen(parmBuf + len);
473
474 }
475
476 ParseOption (opt + 1, (len ? parmBuf : NULL));
477
478 }
479 }
480
481 static void DoAliasing (int fd, int direction)
482 {
483 int bytes;
484 int origBytes;
485 int status;
486 int addrSize;
487 struct ip* ip;
488
489 if (assignAliasAddr) {
490
491 SetAliasAddressFromIfName (ifName);
492 assignAliasAddr = 0;
493 }
494 /*
495 * Get packet from socket.
496 */
497 addrSize = sizeof packetAddr;
498 origBytes = recvfrom (fd,
499 packetBuf,
500 sizeof packetBuf,
501 0,
502 (struct sockaddr*) &packetAddr,
503 &addrSize);
504
505 if (origBytes == -1) {
506
507 if (errno != EINTR)
508 Warn ("read from divert socket failed");
509
510 return;
511 }
512 /*
513 * This is a IP packet.
514 */
515 ip = (struct ip*) packetBuf;
516 if (direction == DONT_KNOW) {
517 if (packetAddr.sin_addr.s_addr == INADDR_ANY)
518 direction = OUTPUT;
519 else
520 direction = INPUT;
521 }
522
523 if (verbose) {
524 /*
525 * Print packet direction and protocol type.
526 */
527 printf (direction == OUTPUT ? "Out " : "In ");
528
529 switch (ip->ip_p) {
530 case IPPROTO_TCP:
531 printf ("[TCP] ");
532 break;
533
534 case IPPROTO_UDP:
535 printf ("[UDP] ");
536 break;
537
538 case IPPROTO_ICMP:
539 printf ("[ICMP] ");
540 break;
541
542 default:
543 printf ("[%d] ", ip->ip_p);
544 break;
545 }
546 /*
547 * Print addresses.
548 */
549 PrintPacket (ip);
550 }
551
552 if (direction == OUTPUT) {
553 /*
554 * Outgoing packets. Do aliasing.
555 */
556 PacketAliasOut (packetBuf, IP_MAXPACKET);
557 }
558 else {
559
560 /*
561 * Do aliasing.
562 */
563 status = PacketAliasIn (packetBuf, IP_MAXPACKET);
564 if (status == PKT_ALIAS_IGNORED &&
565 dropIgnoredIncoming) {
566
567 if (verbose)
568 printf (" dropped.\n");
569
570 if (logDropped)
571 SyslogPacket (ip, LOG_WARNING, "denied");
572
573 return;
574 }
575 }
576 /*
577 * Length might have changed during aliasing.
578 */
579 bytes = ntohs (ip->ip_len);
580 /*
581 * Update alias overhead size for outgoing packets.
582 */
583 if (direction == OUTPUT &&
584 bytes - origBytes > aliasOverhead)
585 aliasOverhead = bytes - origBytes;
586
587 if (verbose) {
588
589 /*
590 * Print addresses after aliasing.
591 */
592 printf (" aliased to\n");
593 printf (" ");
594 PrintPacket (ip);
595 printf ("\n");
596 }
597
598 packetLen = bytes;
599 packetSock = fd;
600 packetDirection = direction;
601
602 FlushPacketBuffer (fd);
603 }
604
605 static void FlushPacketBuffer (int fd)
606 {
607 int wrote;
608 char msgBuf[80];
609 /*
610 * Put packet back for processing.
611 */
612 wrote = sendto (fd,
613 packetBuf,
614 packetLen,
615 0,
616 (struct sockaddr*) &packetAddr,
617 sizeof packetAddr);
618
619 if (wrote != packetLen) {
620 /*
621 * If buffer space is not available,
622 * just return. Main loop will take care of
623 * retrying send when space becomes available.
624 */
625 if (errno == ENOBUFS)
626 return;
627
628 if (errno == EMSGSIZE) {
629
630 if (packetDirection == OUTPUT &&
631 ifMTU != -1)
632 SendNeedFragIcmp (icmpSock,
633 (struct ip*) packetBuf,
634 ifMTU - aliasOverhead);
635 }
636 else {
637
638 sprintf (msgBuf, "failed to write packet back");
639 Warn (msgBuf);
640 }
641 }
642
643 packetSock = -1;
644 }
645
646 static void HandleRoutingInfo (int fd)
647 {
648 int bytes;
649 struct if_msghdr ifMsg;
650 /*
651 * Get packet from socket.
652 */
653 bytes = read (fd, &ifMsg, sizeof ifMsg);
654 if (bytes == -1) {
655
656 Warn ("read from routing socket failed");
657 return;
658 }
659
660 if (ifMsg.ifm_version != RTM_VERSION) {
661
662 Warn ("unexpected packet read from routing socket");
663 return;
664 }
665
666 if (verbose)
667 printf ("Routing message %#x received.\n", ifMsg.ifm_type);
668
669 if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO) &&
670 ifMsg.ifm_index == ifIndex) {
671 if (verbose)
672 printf("Interface address/MTU has probably changed.\n");
673 assignAliasAddr = 1;
674 }
675 }
676
677 static void PrintPacket (struct ip* ip)
678 {
679 printf ("%s", FormatPacket (ip));
680 }
681
682 static void SyslogPacket (struct ip* ip, int priority, const char *label)
683 {
684 syslog (priority, "%s %s", label, FormatPacket (ip));
685 }
686
687 static char* FormatPacket (struct ip* ip)
688 {
689 static char buf[256];
690 struct tcphdr* tcphdr;
691 struct udphdr* udphdr;
692 struct icmp* icmphdr;
693 char src[20];
694 char dst[20];
695
696 strcpy (src, inet_ntoa (ip->ip_src));
697 strcpy (dst, inet_ntoa (ip->ip_dst));
698
699 switch (ip->ip_p) {
700 case IPPROTO_TCP:
701 tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2));
702 sprintf (buf, "[TCP] %s:%d -> %s:%d",
703 src,
704 ntohs (tcphdr->th_sport),
705 dst,
706 ntohs (tcphdr->th_dport));
707 break;
708
709 case IPPROTO_UDP:
710 udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2));
711 sprintf (buf, "[UDP] %s:%d -> %s:%d",
712 src,
713 ntohs (udphdr->uh_sport),
714 dst,
715 ntohs (udphdr->uh_dport));
716 break;
717
718 case IPPROTO_ICMP:
719 icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2));
720 sprintf (buf, "[ICMP] %s -> %s %u(%u)",
721 src,
722 dst,
723 icmphdr->icmp_type,
724 icmphdr->icmp_code);
725 break;
726
727 default:
728 sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst);
729 break;
730 }
731
732 return buf;
733 }
734
735 static void
736 SetAliasAddressFromIfName(const char *ifn)
737 {
738 size_t needed;
739 int mib[6];
740 char *buf, *lim, *next;
741 struct if_msghdr *ifm;
742 struct ifa_msghdr *ifam;
743 struct sockaddr_dl *sdl;
744 struct sockaddr_in *sin;
745
746 mib[0] = CTL_NET;
747 mib[1] = PF_ROUTE;
748 mib[2] = 0;
749 mib[3] = AF_INET; /* Only IP addresses please */
750 mib[4] = NET_RT_IFLIST;
751 mib[5] = 0; /* ifIndex??? */
752 /*
753 * Get interface data.
754 */
755 if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
756 err(1, "iflist-sysctl-estimate");
757 if ((buf = malloc(needed)) == NULL)
758 errx(1, "malloc failed");
759 if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
760 err(1, "iflist-sysctl-get");
761 lim = buf + needed;
762 /*
763 * Loop through interfaces until one with
764 * given name is found. This is done to
765 * find correct interface index for routing
766 * message processing.
767 */
768 ifIndex = 0;
769 next = buf;
770 while (next < lim) {
771 ifm = (struct if_msghdr *)next;
772 next += ifm->ifm_msglen;
773 if (ifm->ifm_version != RTM_VERSION) {
774 if (verbose)
775 warnx("routing message version %d "
776 "not understood", ifm->ifm_version);
777 continue;
778 }
779 if (ifm->ifm_type == RTM_IFINFO) {
780 sdl = (struct sockaddr_dl *)(ifm + 1);
781 if (strlen(ifn) == sdl->sdl_nlen &&
782 strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) {
783 ifIndex = ifm->ifm_index;
784 ifMTU = ifm->ifm_data.ifi_mtu;
785 if (clampMSS)
786 PacketAliasClampMSS(ifMTU - sizeof(struct tcphdr) - sizeof(struct ip));
787 break;
788 }
789 }
790 }
791 if (!ifIndex)
792 errx(1, "unknown interface name %s", ifn);
793 /*
794 * Get interface address.
795 */
796 if (aliasAddr.s_addr == INADDR_NONE) {
797 sin = NULL;
798 while (next < lim) {
799 ifam = (struct ifa_msghdr *)next;
800 next += ifam->ifam_msglen;
801 if (ifam->ifam_version != RTM_VERSION) {
802 if (verbose)
803 warnx("routing message version %d "
804 "not understood", ifam->ifam_version);
805 continue;
806 }
807 if (ifam->ifam_type != RTM_NEWADDR)
808 break;
809 if (ifam->ifam_addrs & RTA_IFA) {
810 int i;
811 char *cp = (char *)(ifam + 1);
812
813 #define ROUNDUP(a) \
814 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
815 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
816
817 for (i = 1; i < RTA_IFA; i <<= 1)
818 if (ifam->ifam_addrs & i)
819 ADVANCE(cp, (struct sockaddr *)cp);
820 if (((struct sockaddr *)cp)->sa_family == AF_INET) {
821 sin = (struct sockaddr_in *)cp;
822 break;
823 }
824 }
825 }
826 if (sin == NULL)
827 errx(1, "%s: cannot get interface address", ifn);
828
829 PacketAliasSetAddress(sin->sin_addr);
830 syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes",
831 inet_ntoa(sin->sin_addr), ifMTU);
832 }
833
834 free(buf);
835 }
836
837 void Quit (const char* msg)
838 {
839 Warn (msg);
840 exit (1);
841 }
842
843 void Warn (const char* msg)
844 {
845 if (background)
846 syslog (LOG_ALERT, "%s (%m)", msg);
847 else
848 warn ("%s", msg);
849 }
850
851 static void RefreshAddr (int sig)
852 {
853 if (ifName)
854 assignAliasAddr = 1;
855 }
856
857 static void InitiateShutdown (int sig)
858 {
859 /*
860 * Start timer to allow kernel gracefully
861 * shutdown existing connections when system
862 * is shut down.
863 */
864 siginterrupt(SIGALRM, 1);
865 signal (SIGALRM, Shutdown);
866 alarm (10);
867 }
868
869 static void Shutdown (int sig)
870 {
871 running = 0;
872 }
873
874 /*
875 * Different options recognized by this program.
876 */
877
878 enum Option {
879
880 PacketAliasOption,
881 Verbose,
882 InPort,
883 OutPort,
884 Port,
885 AliasAddress,
886 TargetAddress,
887 InterfaceName,
888 RedirectPort,
889 RedirectProto,
890 RedirectAddress,
891 ConfigFile,
892 DynamicMode,
893 ClampMSS,
894 ProxyRule,
895 LogDenied,
896 LogFacility,
897 PunchFW
898 };
899
900 enum Param {
901
902 YesNo,
903 Numeric,
904 String,
905 None,
906 Address,
907 Service
908 };
909
910 /*
911 * Option information structure (used by ParseOption).
912 */
913
914 struct OptionInfo {
915
916 enum Option type;
917 int packetAliasOpt;
918 enum Param parm;
919 const char* parmDescription;
920 const char* description;
921 const char* name;
922 const char* shortName;
923 };
924
925 /*
926 * Table of known options.
927 */
928
929 static struct OptionInfo optionTable[] = {
930
931 { PacketAliasOption,
932 PKT_ALIAS_UNREGISTERED_ONLY,
933 YesNo,
934 "[yes|no]",
935 "alias only unregistered addresses",
936 "unregistered_only",
937 "u" },
938
939 { PacketAliasOption,
940 PKT_ALIAS_LOG,
941 YesNo,
942 "[yes|no]",
943 "enable logging",
944 "log",
945 "l" },
946
947 { PacketAliasOption,
948 PKT_ALIAS_PROXY_ONLY,
949 YesNo,
950 "[yes|no]",
951 "proxy only",
952 "proxy_only",
953 NULL },
954
955 { PacketAliasOption,
956 PKT_ALIAS_REVERSE,
957 YesNo,
958 "[yes|no]",
959 "operate in reverse mode",
960 "reverse",
961 NULL },
962
963 { PacketAliasOption,
964 PKT_ALIAS_DENY_INCOMING,
965 YesNo,
966 "[yes|no]",
967 "allow incoming connections",
968 "deny_incoming",
969 "d" },
970
971 { PacketAliasOption,
972 PKT_ALIAS_USE_SOCKETS,
973 YesNo,
974 "[yes|no]",
975 "use sockets to inhibit port conflict",
976 "use_sockets",
977 "s" },
978
979 { PacketAliasOption,
980 PKT_ALIAS_SAME_PORTS,
981 YesNo,
982 "[yes|no]",
983 "try to keep original port numbers for connections",
984 "same_ports",
985 "m" },
986
987 { Verbose,
988 0,
989 YesNo,
990 "[yes|no]",
991 "verbose mode, dump packet information",
992 "verbose",
993 "v" },
994
995 { DynamicMode,
996 0,
997 YesNo,
998 "[yes|no]",
999 "dynamic mode, automatically detect interface address changes",
1000 "dynamic",
1001 NULL },
1002
1003 { ClampMSS,
1004 0,
1005 YesNo,
1006 "[yes|no]",
1007 "enable TCP MSS clamping",
1008 "clamp_mss",
1009 NULL },
1010
1011 { InPort,
1012 0,
1013 Service,
1014 "number|service_name",
1015 "set port for incoming packets",
1016 "in_port",
1017 "i" },
1018
1019 { OutPort,
1020 0,
1021 Service,
1022 "number|service_name",
1023 "set port for outgoing packets",
1024 "out_port",
1025 "o" },
1026
1027 { Port,
1028 0,
1029 Service,
1030 "number|service_name",
1031 "set port (defaults to natd/divert)",
1032 "port",
1033 "p" },
1034
1035 { AliasAddress,
1036 0,
1037 Address,
1038 "x.x.x.x",
1039 "address to use for aliasing",
1040 "alias_address",
1041 "a" },
1042
1043 { TargetAddress,
1044 0,
1045 Address,
1046 "x.x.x.x",
1047 "address to use for incoming sessions",
1048 "target_address",
1049 "t" },
1050
1051 { InterfaceName,
1052 0,
1053 String,
1054 "network_if_name",
1055 "take aliasing address from interface",
1056 "interface",
1057 "n" },
1058
1059 { ProxyRule,
1060 0,
1061 String,
1062 "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
1063 "a.b.c.d:yyyy",
1064 "add transparent proxying / destination NAT",
1065 "proxy_rule",
1066 NULL },
1067
1068 { RedirectPort,
1069 0,
1070 String,
1071 "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
1072 " [remote_addr[:remote_port_range]]",
1073 "redirect a port (or ports) for incoming traffic",
1074 "redirect_port",
1075 NULL },
1076
1077 { RedirectProto,
1078 0,
1079 String,
1080 "proto local_addr [public_addr] [remote_addr]",
1081 "redirect packets of a given proto",
1082 "redirect_proto",
1083 NULL },
1084
1085 { RedirectAddress,
1086 0,
1087 String,
1088 "local_addr[,...] public_addr",
1089 "define mapping between local and public addresses",
1090 "redirect_address",
1091 NULL },
1092
1093 { ConfigFile,
1094 0,
1095 String,
1096 "file_name",
1097 "read options from configuration file",
1098 "config",
1099 "f" },
1100
1101 { LogDenied,
1102 0,
1103 YesNo,
1104 "[yes|no]",
1105 "enable logging of denied incoming packets",
1106 "log_denied",
1107 NULL },
1108
1109 { LogFacility,
1110 0,
1111 String,
1112 "facility",
1113 "name of syslog facility to use for logging",
1114 "log_facility",
1115 NULL },
1116
1117 { PunchFW,
1118 0,
1119 String,
1120 "basenumber:count",
1121 "punch holes in the firewall for incoming FTP/IRC DCC connections",
1122 "punch_fw",
1123 NULL }
1124 };
1125
1126 static void ParseOption (const char* option, const char* parms)
1127 {
1128 int i;
1129 struct OptionInfo* info;
1130 int yesNoValue;
1131 int aliasValue;
1132 int numValue;
1133 u_short uNumValue;
1134 const char* strValue;
1135 struct in_addr addrValue;
1136 int max;
1137 char* end;
1138 CODE* fac_record = NULL;
1139 /*
1140 * Find option from table.
1141 */
1142 max = sizeof (optionTable) / sizeof (struct OptionInfo);
1143 for (i = 0, info = optionTable; i < max; i++, info++) {
1144
1145 if (!strcmp (info->name, option))
1146 break;
1147
1148 if (info->shortName)
1149 if (!strcmp (info->shortName, option))
1150 break;
1151 }
1152
1153 if (i >= max) {
1154
1155 warnx ("unknown option %s", option);
1156 Usage ();
1157 }
1158
1159 uNumValue = 0;
1160 yesNoValue = 0;
1161 numValue = 0;
1162 strValue = NULL;
1163 /*
1164 * Check parameters.
1165 */
1166 switch (info->parm) {
1167 case YesNo:
1168 if (!parms)
1169 parms = "yes";
1170
1171 if (!strcmp (parms, "yes"))
1172 yesNoValue = 1;
1173 else
1174 if (!strcmp (parms, "no"))
1175 yesNoValue = 0;
1176 else
1177 errx (1, "%s needs yes/no parameter", option);
1178 break;
1179
1180 case Service:
1181 if (!parms)
1182 errx (1, "%s needs service name or "
1183 "port number parameter",
1184 option);
1185
1186 uNumValue = StrToPort (parms, "divert");
1187 break;
1188
1189 case Numeric:
1190 if (parms)
1191 numValue = strtol (parms, &end, 10);
1192 else
1193 end = NULL;
1194
1195 if (end == parms)
1196 errx (1, "%s needs numeric parameter", option);
1197 break;
1198
1199 case String:
1200 strValue = parms;
1201 if (!strValue)
1202 errx (1, "%s needs parameter", option);
1203 break;
1204
1205 case None:
1206 if (parms)
1207 errx (1, "%s does not take parameters", option);
1208 break;
1209
1210 case Address:
1211 if (!parms)
1212 errx (1, "%s needs address/host parameter", option);
1213
1214 StrToAddr (parms, &addrValue);
1215 break;
1216 }
1217
1218 switch (info->type) {
1219 case PacketAliasOption:
1220
1221 aliasValue = yesNoValue ? info->packetAliasOpt : 0;
1222 PacketAliasSetMode (aliasValue, info->packetAliasOpt);
1223 break;
1224
1225 case Verbose:
1226 verbose = yesNoValue;
1227 break;
1228
1229 case DynamicMode:
1230 dynamicMode = yesNoValue;
1231 break;
1232
1233 case ClampMSS:
1234 clampMSS = yesNoValue;
1235 break;
1236
1237 case InPort:
1238 inPort = uNumValue;
1239 break;
1240
1241 case OutPort:
1242 outPort = uNumValue;
1243 break;
1244
1245 case Port:
1246 inOutPort = uNumValue;
1247 break;
1248
1249 case AliasAddress:
1250 memcpy (&aliasAddr, &addrValue, sizeof (struct in_addr));
1251 break;
1252
1253 case TargetAddress:
1254 PacketAliasSetTarget(addrValue);
1255 break;
1256
1257 case RedirectPort:
1258 SetupPortRedirect (strValue);
1259 break;
1260
1261 case RedirectProto:
1262 SetupProtoRedirect(strValue);
1263 break;
1264
1265 case RedirectAddress:
1266 SetupAddressRedirect (strValue);
1267 break;
1268
1269 case ProxyRule:
1270 PacketAliasProxyRule (strValue);
1271 break;
1272
1273 case InterfaceName:
1274 if (ifName)
1275 free (ifName);
1276
1277 ifName = strdup (strValue);
1278 break;
1279
1280 case ConfigFile:
1281 ReadConfigFile (strValue);
1282 break;
1283
1284 case LogDenied:
1285 logDropped = 1;
1286 break;
1287
1288 case LogFacility:
1289
1290 fac_record = facilitynames;
1291 while (fac_record->c_name != NULL) {
1292
1293 if (!strcmp (fac_record->c_name, strValue)) {
1294
1295 logFacility = fac_record->c_val;
1296 break;
1297
1298 }
1299 else
1300 fac_record++;
1301 }
1302
1303 if(fac_record->c_name == NULL)
1304 errx(1, "Unknown log facility name: %s", strValue);
1305
1306 break;
1307
1308 case PunchFW:
1309 SetupPunchFW(strValue);
1310 break;
1311 }
1312 }
1313
1314 void ReadConfigFile (const char* fileName)
1315 {
1316 FILE* file;
1317 char *buf;
1318 size_t len;
1319 char *ptr, *p;
1320 char* option;
1321
1322 file = fopen (fileName, "r");
1323 if (!file)
1324 err(1, "cannot open config file %s", fileName);
1325
1326 while ((buf = fgetln(file, &len)) != NULL) {
1327 if (buf[len - 1] == '\n')
1328 buf[len - 1] = '\0';
1329 else
1330 errx(1, "config file format error: "
1331 "last line should end with newline");
1332
1333 /*
1334 * Check for comments, strip off trailing spaces.
1335 */
1336 if ((ptr = strchr(buf, '#')))
1337 *ptr = '\0';
1338 for (ptr = buf; isspace(*ptr); ++ptr)
1339 continue;
1340 if (*ptr == '\0')
1341 continue;
1342 for (p = strchr(buf, '\0'); isspace(*--p);)
1343 continue;
1344 *++p = '\0';
1345
1346 /*
1347 * Extract option name.
1348 */
1349 option = ptr;
1350 while (*ptr && !isspace (*ptr))
1351 ++ptr;
1352
1353 if (*ptr != '\0') {
1354
1355 *ptr = '\0';
1356 ++ptr;
1357 }
1358 /*
1359 * Skip white space between name and parms.
1360 */
1361 while (*ptr && isspace (*ptr))
1362 ++ptr;
1363
1364 ParseOption (option, *ptr ? ptr : NULL);
1365 }
1366
1367 fclose (file);
1368 }
1369
1370 static void Usage ()
1371 {
1372 int i;
1373 int max;
1374 struct OptionInfo* info;
1375
1376 fprintf (stderr, "Recognized options:\n\n");
1377
1378 max = sizeof (optionTable) / sizeof (struct OptionInfo);
1379 for (i = 0, info = optionTable; i < max; i++, info++) {
1380
1381 fprintf (stderr, "-%-20s %s\n", info->name,
1382 info->parmDescription);
1383
1384 if (info->shortName)
1385 fprintf (stderr, "-%-20s %s\n", info->shortName,
1386 info->parmDescription);
1387
1388 fprintf (stderr, " %s\n\n", info->description);
1389 }
1390
1391 exit (1);
1392 }
1393
1394 void SetupPortRedirect (const char* parms)
1395 {
1396 char buf[128];
1397 char* ptr;
1398 char* serverPool;
1399 struct in_addr localAddr;
1400 struct in_addr publicAddr;
1401 struct in_addr remoteAddr;
1402 port_range portRange;
1403 u_short localPort = 0;
1404 u_short publicPort = 0;
1405 u_short remotePort = 0;
1406 u_short numLocalPorts = 0;
1407 u_short numPublicPorts = 0;
1408 u_short numRemotePorts = 0;
1409 int proto;
1410 char* protoName;
1411 char* separator;
1412 int i;
1413 struct alias_link *link = NULL;
1414
1415 strcpy (buf, parms);
1416 /*
1417 * Extract protocol.
1418 */
1419 protoName = strtok (buf, " \t");
1420 if (!protoName)
1421 errx (1, "redirect_port: missing protocol");
1422
1423 proto = StrToProto (protoName);
1424 /*
1425 * Extract local address.
1426 */
1427 ptr = strtok (NULL, " \t");
1428 if (!ptr)
1429 errx (1, "redirect_port: missing local address");
1430
1431 separator = strchr(ptr, ',');
1432 if (separator) { /* LSNAT redirection syntax. */
1433 localAddr.s_addr = INADDR_NONE;
1434 localPort = ~0;
1435 numLocalPorts = 1;
1436 serverPool = ptr;
1437 } else {
1438 if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 )
1439 errx (1, "redirect_port: invalid local port range");
1440
1441 localPort = GETLOPORT(portRange);
1442 numLocalPorts = GETNUMPORTS(portRange);
1443 serverPool = NULL;
1444 }
1445
1446 /*
1447 * Extract public port and optionally address.
1448 */
1449 ptr = strtok (NULL, " \t");
1450 if (!ptr)
1451 errx (1, "redirect_port: missing public port");
1452
1453 separator = strchr (ptr, ':');
1454 if (separator) {
1455 if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 )
1456 errx (1, "redirect_port: invalid public port range");
1457 }
1458 else {
1459 publicAddr.s_addr = INADDR_ANY;
1460 if (StrToPortRange (ptr, protoName, &portRange) != 0)
1461 errx (1, "redirect_port: invalid public port range");
1462 }
1463
1464 publicPort = GETLOPORT(portRange);
1465 numPublicPorts = GETNUMPORTS(portRange);
1466
1467 /*
1468 * Extract remote address and optionally port.
1469 */
1470 ptr = strtok (NULL, " \t");
1471 if (ptr) {
1472 separator = strchr (ptr, ':');
1473 if (separator) {
1474 if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0)
1475 errx (1, "redirect_port: invalid remote port range");
1476 } else {
1477 SETLOPORT(portRange, 0);
1478 SETNUMPORTS(portRange, 1);
1479 StrToAddr (ptr, &remoteAddr);
1480 }
1481 }
1482 else {
1483 SETLOPORT(portRange, 0);
1484 SETNUMPORTS(portRange, 1);
1485 remoteAddr.s_addr = INADDR_ANY;
1486 }
1487
1488 remotePort = GETLOPORT(portRange);
1489 numRemotePorts = GETNUMPORTS(portRange);
1490
1491 /*
1492 * Make sure port ranges match up, then add the redirect ports.
1493 */
1494 if (numLocalPorts != numPublicPorts)
1495 errx (1, "redirect_port: port ranges must be equal in size");
1496
1497 /* Remote port range is allowed to be '0' which means all ports. */
1498 if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0))
1499 errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
1500
1501 for (i = 0 ; i < numPublicPorts ; ++i) {
1502 /* If remotePort is all ports, set it to 0. */
1503 u_short remotePortCopy = remotePort + i;
1504 if (numRemotePorts == 1 && remotePort == 0)
1505 remotePortCopy = 0;
1506
1507 link = PacketAliasRedirectPort (localAddr,
1508 htons(localPort + i),
1509 remoteAddr,
1510 htons(remotePortCopy),
1511 publicAddr,
1512 htons(publicPort + i),
1513 proto);
1514 }
1515
1516 /*
1517 * Setup LSNAT server pool.
1518 */
1519 if (serverPool != NULL && link != NULL) {
1520 ptr = strtok(serverPool, ",");
1521 while (ptr != NULL) {
1522 if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0)
1523 errx(1, "redirect_port: invalid local port range");
1524
1525 localPort = GETLOPORT(portRange);
1526 if (GETNUMPORTS(portRange) != 1)
1527 errx(1, "redirect_port: local port must be single in this context");
1528 PacketAliasAddServer(link, localAddr, htons(localPort));
1529 ptr = strtok(NULL, ",");
1530 }
1531 }
1532 }
1533
1534 void
1535 SetupProtoRedirect(const char* parms)
1536 {
1537 char buf[128];
1538 char* ptr;
1539 struct in_addr localAddr;
1540 struct in_addr publicAddr;
1541 struct in_addr remoteAddr;
1542 int proto;
1543 char* protoName;
1544 struct protoent *protoent;
1545
1546 strcpy (buf, parms);
1547 /*
1548 * Extract protocol.
1549 */
1550 protoName = strtok(buf, " \t");
1551 if (!protoName)
1552 errx(1, "redirect_proto: missing protocol");
1553
1554 protoent = getprotobyname(protoName);
1555 if (protoent == NULL)
1556 errx(1, "redirect_proto: unknown protocol %s", protoName);
1557 else
1558 proto = protoent->p_proto;
1559 /*
1560 * Extract local address.
1561 */
1562 ptr = strtok(NULL, " \t");
1563 if (!ptr)
1564 errx(1, "redirect_proto: missing local address");
1565 else
1566 StrToAddr(ptr, &localAddr);
1567 /*
1568 * Extract optional public address.
1569 */
1570 ptr = strtok(NULL, " \t");
1571 if (ptr)
1572 StrToAddr(ptr, &publicAddr);
1573 else
1574 publicAddr.s_addr = INADDR_ANY;
1575 /*
1576 * Extract optional remote address.
1577 */
1578 ptr = strtok(NULL, " \t");
1579 if (ptr)
1580 StrToAddr(ptr, &remoteAddr);
1581 else
1582 remoteAddr.s_addr = INADDR_ANY;
1583 /*
1584 * Create aliasing link.
1585 */
1586 (void)PacketAliasRedirectProto(localAddr, remoteAddr, publicAddr,
1587 proto);
1588 }
1589
1590 void SetupAddressRedirect (const char* parms)
1591 {
1592 char buf[128];
1593 char* ptr;
1594 char* separator;
1595 struct in_addr localAddr;
1596 struct in_addr publicAddr;
1597 char* serverPool;
1598 struct alias_link *link;
1599
1600 strcpy (buf, parms);
1601 /*
1602 * Extract local address.
1603 */
1604 ptr = strtok (buf, " \t");
1605 if (!ptr)
1606 errx (1, "redirect_address: missing local address");
1607
1608 separator = strchr(ptr, ',');
1609 if (separator) { /* LSNAT redirection syntax. */
1610 localAddr.s_addr = INADDR_NONE;
1611 serverPool = ptr;
1612 } else {
1613 StrToAddr (ptr, &localAddr);
1614 serverPool = NULL;
1615 }
1616 /*
1617 * Extract public address.
1618 */
1619 ptr = strtok (NULL, " \t");
1620 if (!ptr)
1621 errx (1, "redirect_address: missing public address");
1622
1623 StrToAddr (ptr, &publicAddr);
1624 link = PacketAliasRedirectAddr(localAddr, publicAddr);
1625
1626 /*
1627 * Setup LSNAT server pool.
1628 */
1629 if (serverPool != NULL && link != NULL) {
1630 ptr = strtok(serverPool, ",");
1631 while (ptr != NULL) {
1632 StrToAddr(ptr, &localAddr);
1633 PacketAliasAddServer(link, localAddr, htons(~0));
1634 ptr = strtok(NULL, ",");
1635 }
1636 }
1637 }
1638
1639 void StrToAddr (const char* str, struct in_addr* addr)
1640 {
1641 struct hostent* hp;
1642
1643 if (inet_aton (str, addr))
1644 return;
1645
1646 hp = gethostbyname (str);
1647 if (!hp)
1648 errx (1, "unknown host %s", str);
1649
1650 memcpy (addr, hp->h_addr, sizeof (struct in_addr));
1651 }
1652
1653 u_short StrToPort (const char* str, const char* proto)
1654 {
1655 u_short port;
1656 struct servent* sp;
1657 char* end;
1658
1659 port = strtol (str, &end, 10);
1660 if (end != str)
1661 return htons (port);
1662
1663 sp = getservbyname (str, proto);
1664 if (!sp)
1665 errx (1, "unknown service %s/%s", str, proto);
1666
1667 return sp->s_port;
1668 }
1669
1670 int StrToPortRange (const char* str, const char* proto, port_range *portRange)
1671 {
1672 char* sep;
1673 struct servent* sp;
1674 char* end;
1675 u_short loPort;
1676 u_short hiPort;
1677
1678 /* First see if this is a service, return corresponding port if so. */
1679 sp = getservbyname (str,proto);
1680 if (sp) {
1681 SETLOPORT(*portRange, ntohs(sp->s_port));
1682 SETNUMPORTS(*portRange, 1);
1683 return 0;
1684 }
1685
1686 /* Not a service, see if it's a single port or port range. */
1687 sep = strchr (str, '-');
1688 if (sep == NULL) {
1689 SETLOPORT(*portRange, strtol(str, &end, 10));
1690 if (end != str) {
1691 /* Single port. */
1692 SETNUMPORTS(*portRange, 1);
1693 return 0;
1694 }
1695
1696 /* Error in port range field. */
1697 errx (1, "unknown service %s/%s", str, proto);
1698 }
1699
1700 /* Port range, get the values and sanity check. */
1701 sscanf (str, "%hu-%hu", &loPort, &hiPort);
1702 SETLOPORT(*portRange, loPort);
1703 SETNUMPORTS(*portRange, 0); /* Error by default */
1704 if (loPort <= hiPort)
1705 SETNUMPORTS(*portRange, hiPort - loPort + 1);
1706
1707 if (GETNUMPORTS(*portRange) == 0)
1708 errx (1, "invalid port range %s", str);
1709
1710 return 0;
1711 }
1712
1713
1714 int StrToProto (const char* str)
1715 {
1716 if (!strcmp (str, "tcp"))
1717 return IPPROTO_TCP;
1718
1719 if (!strcmp (str, "udp"))
1720 return IPPROTO_UDP;
1721
1722 errx (1, "unknown protocol %s. Expected tcp or udp", str);
1723 }
1724
1725 int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange)
1726 {
1727 char* ptr;
1728
1729 ptr = strchr (str, ':');
1730 if (!ptr)
1731 errx (1, "%s is missing port number", str);
1732
1733 *ptr = '\0';
1734 ++ptr;
1735
1736 StrToAddr (str, addr);
1737 return StrToPortRange (ptr, proto, portRange);
1738 }
1739
1740 static void
1741 SetupPunchFW(const char *strValue)
1742 {
1743 unsigned int base, num;
1744
1745 if (sscanf(strValue, "%u:%u", &base, &num) != 2)
1746 errx(1, "punch_fw: basenumber:count parameter required");
1747
1748 PacketAliasSetFWBase(base, num);
1749 (void)PacketAliasSetMode(PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);
1750 }