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