Deleted Added
sdiff udiff text old ( 124621 ) new ( 127094 )
full compact
1/* -*- mode: c; tab-width: 8; c-basic-indent: 4; -*- */
2
3/*-
4 * Copyright (c) 2001 Charles Mott <cm@linktel.net>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright

--- 11 unchanged lines hidden (view full) ---

22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: head/sys/netinet/libalias/alias_db.c 124621 2004-01-17 10:52:21Z phk $");
31
32/*
33 Alias_db.c encapsulates all data structures used for storing
34 packet aliasing data. Other parts of the aliasing software
35 access data through functions provided in this file.
36
37 Data storage is based on the notion of a "link", which is
38 established for ICMP echo/reply packets, UDP datagrams and

--- 123 unchanged lines hidden (view full) ---

162#include <netinet/ip.h>
163#include <netinet/tcp.h>
164#include <arpa/inet.h>
165
166#include "alias.h"
167#include "alias_local.h"
168
169
170static LIST_HEAD(, libalias) instancehead = LIST_HEAD_INITIALIZER(instancehead);
171
172
173/*
174 Constants (note: constants are also defined
175 near relevant functions or structs)
176*/
177
178/* Parameters used for cleanup of expired links */

--- 6 unchanged lines hidden (view full) ---

185#define PROTO_EXPIRE_TIME 60
186#define FRAGMENT_ID_EXPIRE_TIME 10
187#define FRAGMENT_PTR_EXPIRE_TIME 30
188
189/* TCP link expire time for different cases */
190/* When the link has been used and closed - minimal grace time to
191 allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */
192#ifndef TCP_EXPIRE_DEAD
193# define TCP_EXPIRE_DEAD 10
194#endif
195
196/* When the link has been used and closed on one side - the other side
197 is allowed to still send data */
198#ifndef TCP_EXPIRE_SINGLEDEAD
199# define TCP_EXPIRE_SINGLEDEAD 90
200#endif
201
202/* When the link isn't yet up */
203#ifndef TCP_EXPIRE_INITIAL
204# define TCP_EXPIRE_INITIAL 300
205#endif
206
207/* When the link is up */
208#ifndef TCP_EXPIRE_CONNECTED
209# define TCP_EXPIRE_CONNECTED 86400
210#endif
211
212
213/* Dummy port number codes used for FindLinkIn/Out() and AddLink().
214 These constants can be anything except zero, which indicates an
215 unknown port number. */
216
217#define NO_DEST_PORT 1

--- 23 unchanged lines hidden (view full) ---

241 The link records support two independent chainings. Lookup
242 tables for input and out tables hold the initial pointers
243 the link chains. On input, the lookup table indexes on alias
244 port and link type. On output, the lookup table indexes on
245 source address, destination address, source port, destination
246 port and link type.
247*/
248
249struct ack_data_record /* used to save changes to ACK/sequence numbers */
250{
251 u_long ack_old;
252 u_long ack_new;
253 int delta;
254 int active;
255};
256
257struct tcp_state /* Information about TCP connection */
258{
259 int in; /* State for outside -> inside */
260 int out; /* State for inside -> outside */
261 int index; /* Index to ACK data array */
262 int ack_modified; /* Indicates whether ACK and sequence numbers */
263 /* been modified */
264};
265
266#define N_LINK_TCP_DATA 3 /* Number of distinct ACK number changes
267 saved for a modified TCP stream */
268struct tcp_dat
269{
270 struct tcp_state state;
271 struct ack_data_record ack[N_LINK_TCP_DATA];
272 int fwhole; /* Which firewall record is used for this hole? */
273};
274
275struct server /* LSNAT server pool (circular list) */
276{
277 struct in_addr addr;
278 u_short port;
279 struct server *next;
280};
281
282struct alias_link /* Main data structure */
283{
284 struct libalias *la;
285 struct in_addr src_addr; /* Address and port information */
286 struct in_addr dst_addr;
287 struct in_addr alias_addr;
288 struct in_addr proxy_addr;
289 u_short src_port;
290 u_short dst_port;
291 u_short alias_port;
292 u_short proxy_port;
293 struct server *server;
294
295 int link_type; /* Type of link: TCP, UDP, ICMP, proto, frag */
296
297/* values for link_type */
298#define LINK_ICMP IPPROTO_ICMP
299#define LINK_UDP IPPROTO_UDP
300#define LINK_TCP IPPROTO_TCP
301#define LINK_FRAGMENT_ID (IPPROTO_MAX + 1)
302#define LINK_FRAGMENT_PTR (IPPROTO_MAX + 2)
303#define LINK_ADDR (IPPROTO_MAX + 3)
304#define LINK_PPTP (IPPROTO_MAX + 4)
305
306 int flags; /* indicates special characteristics */
307 int pflags; /* protocol-specific flags */
308
309/* flag bits */
310#define LINK_UNKNOWN_DEST_PORT 0x01
311#define LINK_UNKNOWN_DEST_ADDR 0x02
312#define LINK_PERMANENT 0x04
313#define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */
314#define LINK_UNFIREWALLED 0x08
315
316 int timestamp; /* Time link was last accessed */
317 int expire_time; /* Expire time for link */
318
319 int sockfd; /* socket descriptor */
320
321 LIST_ENTRY(alias_link) list_out; /* Linked list of pointers for */
322 LIST_ENTRY(alias_link) list_in; /* input and output lookup tables */
323
324 union /* Auxiliary data */
325 {
326 char *frag_ptr;
327 struct in_addr frag_addr;
328 struct tcp_dat *tcp;
329 } data;
330};
331
332/* Internal utility routines (used only in alias_db.c)
333
334Lookup table starting points:
335 StartPointIn() -- link table initial search point for
336 incoming packets
337 StartPointOut() -- link table initial search point for
338 outgoing packets
339
340Miscellaneous:
341 SeqDiff() -- difference between two TCP sequences
342 ShowAliasStats() -- send alias statistics to a monitor file
343*/
344
345
346/* Local prototypes */
347static u_int StartPointIn(struct in_addr, u_short, int);
348
349static u_int StartPointOut(struct in_addr, struct in_addr,
350 u_short, u_short, int);
351
352static int SeqDiff(u_long, u_long);
353
354static void ShowAliasStats(struct libalias *);
355
356#ifndef NO_FW_PUNCH
357/* Firewall control */
358static void InitPunchFW(struct libalias *la);
359static void UninitPunchFW(struct libalias *la);
360static void ClearFWHole(struct alias_link *link);
361#endif
362
363/* Log file control */
364static void InitPacketAliasLog(struct libalias *la);
365static void UninitPacketAliasLog(struct libalias *la);
366
367static u_int
368StartPointIn(struct in_addr alias_addr,
369 u_short alias_port,
370 int link_type)
371{
372 u_int n;
373
374 n = alias_addr.s_addr;
375 if (link_type != LINK_PPTP)
376 n += alias_port;
377 n += link_type;
378 return(n % LINK_TABLE_IN_SIZE);
379}
380
381
382static u_int
383StartPointOut(struct in_addr src_addr, struct in_addr dst_addr,
384 u_short src_port, u_short dst_port, int link_type)
385{
386 u_int n;
387
388 n = src_addr.s_addr;
389 n += dst_addr.s_addr;
390 if (link_type != LINK_PPTP) {
391 n += src_port;
392 n += dst_port;
393 }
394 n += link_type;
395
396 return(n % LINK_TABLE_OUT_SIZE);
397}
398
399
400static int
401SeqDiff(u_long x, u_long y)
402{
403/* Return the difference between two TCP sequence numbers */
404
405/*
406 This function is encapsulated in case there are any unusual
407 arithmetic conditions that need to be considered.
408*/
409
410 return (ntohl(y) - ntohl(x));
411}
412
413
414static void
415ShowAliasStats(struct libalias *la)
416{
417/* Used for debugging */
418
419 if (la->monitorFile)
420 {
421 fprintf(la->monitorFile,
422 "icmp=%d, udp=%d, tcp=%d, pptp=%d, proto=%d, frag_id=%d frag_ptr=%d",
423 la->icmpLinkCount,
424 la->udpLinkCount,
425 la->tcpLinkCount,
426 la->pptpLinkCount,
427 la->protoLinkCount,
428 la->fragmentIdLinkCount,
429 la->fragmentPtrLinkCount);
430
431 fprintf(la->monitorFile, " / tot=%d (sock=%d)\n",
432 la->icmpLinkCount + la->udpLinkCount
433 + la->tcpLinkCount
434 + la->pptpLinkCount
435 + la->protoLinkCount
436 + la->fragmentIdLinkCount
437 + la->fragmentPtrLinkCount,
438 la->sockCount);
439
440 fflush(la->monitorFile);
441 }
442}
443
444
445
446
447
448/* Internal routines for finding, deleting and adding links
449

--- 12 unchanged lines hidden (view full) ---

462 FindLinkOut() - find link for outgoing packets
463 FindLinkIn() - find link for incoming packets
464
465Port search:
466 FindNewPortGroup() - find an available group of ports
467*/
468
469/* Local prototypes */
470static int GetNewPort(struct libalias *, struct alias_link *, int);
471
472static u_short GetSocket(struct libalias *, u_short, int *, int);
473
474static void CleanupAliasData(struct libalias *);
475
476static void IncrementalCleanup(struct libalias *);
477
478static void DeleteLink(struct alias_link *);
479
480static struct alias_link *
481AddLink(struct libalias *, struct in_addr, struct in_addr, struct in_addr,
482 u_short, u_short, int, int);
483
484static struct alias_link *
485ReLink(struct alias_link *,
486 struct in_addr, struct in_addr, struct in_addr,
487 u_short, u_short, int, int);
488
489static struct alias_link *
490FindLinkOut(struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
491
492static struct alias_link *
493FindLinkIn(struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
494
495
496#define ALIAS_PORT_BASE 0x08000
497#define ALIAS_PORT_MASK 0x07fff
498#define ALIAS_PORT_MASK_EVEN 0x07ffe
499#define GET_NEW_PORT_MAX_ATTEMPTS 20
500
501#define GET_ALIAS_PORT -1

--- 4 unchanged lines hidden (view full) ---

506/* GetNewPort() allocates port numbers. Note that if a port number
507 is already in use, that does not mean that it cannot be used by
508 another link concurrently. This is because GetNewPort() looks for
509 unused triplets: (dest addr, dest port, alias port). */
510
511static int
512GetNewPort(struct libalias *la, struct alias_link *link, int alias_port_param)
513{
514 int i;
515 int max_trials;
516 u_short port_sys;
517 u_short port_net;
518
519/*
520 Description of alias_port_param for GetNewPort(). When
521 this parameter is zero or positive, it precisely specifies
522 the port number. GetNewPort() will return this number
523 without check that it is in use.
524
525 When this parameter is GET_ALIAS_PORT, it indicates to get a randomly
526 selected port number.
527*/
528
529 if (alias_port_param == GET_ALIAS_PORT)
530 {
531 /*
532 * The aliasing port is automatically selected
533 * by one of two methods below:
534 */
535 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
536
537 if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS)
538 {
539 /*
540 * When the PKT_ALIAS_SAME_PORTS option is
541 * chosen, the first try will be the
542 * actual source port. If this is already
543 * in use, the remainder of the trials
544 * will be random.
545 */
546 port_net = link->src_port;
547 port_sys = ntohs(port_net);
548 }
549 else
550 {
551 /* First trial and all subsequent are random. */
552 port_sys = random() & ALIAS_PORT_MASK;
553 port_sys += ALIAS_PORT_BASE;
554 port_net = htons(port_sys);
555 }
556 }
557 else if (alias_port_param >= 0 && alias_port_param < 0x10000)
558 {
559 link->alias_port = (u_short) alias_port_param;
560 return(0);
561 }
562 else
563 {
564#ifdef DEBUG
565 fprintf(stderr, "PacketAlias/GetNewPort(): ");
566 fprintf(stderr, "input parameter error\n");
567#endif
568 return(-1);
569 }
570
571
572/* Port number search */
573 for (i=0; i<max_trials; i++)
574 {
575 int go_ahead;
576 struct alias_link *search_result;
577
578 search_result = FindLinkIn(la, link->dst_addr, link->alias_addr,
579 link->dst_port, port_net,
580 link->link_type, 0);
581
582 if (search_result == NULL)
583 go_ahead = 1;
584 else if (!(link->flags & LINK_PARTIALLY_SPECIFIED)
585 && (search_result->flags & LINK_PARTIALLY_SPECIFIED))
586 go_ahead = 1;
587 else
588 go_ahead = 0;
589
590 if (go_ahead)
591 {
592 if ((la->packetAliasMode & PKT_ALIAS_USE_SOCKETS)
593 && (link->flags & LINK_PARTIALLY_SPECIFIED)
594 && ((link->link_type == LINK_TCP) ||
595 (link->link_type == LINK_UDP)))
596 {
597 if (GetSocket(la, port_net, &link->sockfd, link->link_type))
598 {
599 link->alias_port = port_net;
600 return(0);
601 }
602 }
603 else
604 {
605 link->alias_port = port_net;
606 return(0);
607 }
608 }
609
610 port_sys = random() & ALIAS_PORT_MASK;
611 port_sys += ALIAS_PORT_BASE;
612 port_net = htons(port_sys);
613 }
614
615#ifdef DEBUG
616 fprintf(stderr, "PacketAlias/GetnewPort(): ");
617 fprintf(stderr, "could not find free port\n");
618#endif
619
620 return(-1);
621}
622
623
624static u_short
625GetSocket(struct libalias *la, u_short port_net, int *sockfd, int link_type)
626{
627 int err;
628 int sock;
629 struct sockaddr_in sock_addr;
630
631 if (link_type == LINK_TCP)
632 sock = socket(AF_INET, SOCK_STREAM, 0);
633 else if (link_type == LINK_UDP)
634 sock = socket(AF_INET, SOCK_DGRAM, 0);
635 else
636 {
637#ifdef DEBUG
638 fprintf(stderr, "PacketAlias/GetSocket(): ");
639 fprintf(stderr, "incorrect link type\n");
640#endif
641 return(0);
642 }
643
644 if (sock < 0)
645 {
646#ifdef DEBUG
647 fprintf(stderr, "PacketAlias/GetSocket(): ");
648 fprintf(stderr, "socket() error %d\n", *sockfd);
649#endif
650 return(0);
651 }
652
653 sock_addr.sin_family = AF_INET;
654 sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
655 sock_addr.sin_port = port_net;
656
657 err = bind(sock,
658 (struct sockaddr *) &sock_addr,
659 sizeof(sock_addr));
660 if (err == 0)
661 {
662 la->sockCount++;
663 *sockfd = sock;
664 return(1);
665 }
666 else
667 {
668 close(sock);
669 return(0);
670 }
671}
672
673
674/* FindNewPortGroup() returns a base port number for an available
675 range of contiguous port numbers. Note that if a port number
676 is already in use, that does not mean that it cannot be used by
677 another link concurrently. This is because FindNewPortGroup()
678 looks for unused triplets: (dest addr, dest port, alias port). */
679
680int
681FindNewPortGroup(struct libalias *la,
682 struct in_addr dst_addr,
683 struct in_addr alias_addr,
684 u_short src_port,
685 u_short dst_port,
686 u_short port_count,
687 u_char proto,
688 u_char align)
689{
690 int i, j;
691 int max_trials;
692 u_short port_sys;
693 int link_type;
694
695 /*
696 * Get link_type from protocol
697 */
698
699 switch (proto)
700 {
701 case IPPROTO_UDP:
702 link_type = LINK_UDP;
703 break;
704 case IPPROTO_TCP:
705 link_type = LINK_TCP;
706 break;
707 default:
708 return (0);
709 break;
710 }
711
712 /*
713 * The aliasing port is automatically selected
714 * by one of two methods below:
715 */
716 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
717
718 if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
719 /*
720 * When the ALIAS_SAME_PORTS option is
721 * chosen, the first try will be the
722 * actual source port. If this is already
723 * in use, the remainder of the trials
724 * will be random.
725 */
726 port_sys = ntohs(src_port);
727
728 } else {
729
730 /* First trial and all subsequent are random. */
731 if (align == FIND_EVEN_ALIAS_BASE)
732 port_sys = random() & ALIAS_PORT_MASK_EVEN;
733 else
734 port_sys = random() & ALIAS_PORT_MASK;
735
736 port_sys += ALIAS_PORT_BASE;
737 }
738
739/* Port number search */
740 for (i = 0; i < max_trials; i++) {
741
742 struct alias_link *search_result;
743
744 for (j = 0; j < port_count; j++)
745 if (0 != (search_result = FindLinkIn(la, dst_addr, alias_addr,
746 dst_port, htons(port_sys + j),
747 link_type, 0)))
748 break;
749
750 /* Found a good range, return base */
751 if (j == port_count)
752 return (htons(port_sys));
753
754 /* Find a new base to try */
755 if (align == FIND_EVEN_ALIAS_BASE)
756 port_sys = random() & ALIAS_PORT_MASK_EVEN;
757 else
758 port_sys = random() & ALIAS_PORT_MASK;
759
760 port_sys += ALIAS_PORT_BASE;
761 }
762
763#ifdef DEBUG
764 fprintf(stderr, "PacketAlias/FindNewPortGroup(): ");
765 fprintf(stderr, "could not find free port(s)\n");
766#endif
767
768 return(0);
769}
770
771static void
772CleanupAliasData(struct libalias *la)
773{
774 struct alias_link *link;
775 int i, icount;
776
777 icount = 0;
778 for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
779 {
780 link = LIST_FIRST(&la->linkTableOut[i]);
781 while (link != NULL)
782 {
783 struct alias_link *link_next;
784 link_next = LIST_NEXT(link, list_out);
785 icount++;
786 DeleteLink(link);
787 link = link_next;
788 }
789 }
790
791 la->cleanupIndex =0;
792}
793
794
795static void
796IncrementalCleanup(struct libalias *la)
797{
798 int icount;
799 struct alias_link *link;
800
801 icount = 0;
802 link = LIST_FIRST(&la->linkTableOut[la->cleanupIndex++]);
803 while (link != NULL)
804 {
805 int idelta;
806 struct alias_link *link_next;
807
808 link_next = LIST_NEXT(link, list_out);
809 idelta = la->timeStamp - link->timestamp;
810 switch (link->link_type)
811 {
812 case LINK_TCP:
813 if (idelta > link->expire_time)
814 {
815 struct tcp_dat *tcp_aux;
816
817 tcp_aux = link->data.tcp;
818 if (tcp_aux->state.in != ALIAS_TCP_STATE_CONNECTED
819 || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED)
820 {
821 DeleteLink(link);
822 icount++;
823 }
824 }
825 break;
826 default:
827 if (idelta > link->expire_time)
828 {
829 DeleteLink(link);
830 icount++;
831 }
832 break;
833 }
834 link = link_next;
835 }
836
837 if (la->cleanupIndex == LINK_TABLE_OUT_SIZE)
838 la->cleanupIndex = 0;
839}
840
841static void
842DeleteLink(struct alias_link *link)
843{
844 struct libalias *la = link->la;
845
846/* Don't do anything if the link is marked permanent */
847 if (la->deleteAllLinks == 0 && link->flags & LINK_PERMANENT)
848 return;
849
850#ifndef NO_FW_PUNCH
851/* Delete associated firewall hole, if any */
852 ClearFWHole(link);
853#endif
854
855/* Free memory allocated for LSNAT server pool */
856 if (link->server != NULL) {
857 struct server *head, *curr, *next;
858
859 head = curr = link->server;
860 do {
861 next = curr->next;
862 free(curr);
863 } while ((curr = next) != head);
864 }
865
866/* Adjust output table pointers */
867 LIST_REMOVE(link, list_out);
868
869/* Adjust input table pointers */
870 LIST_REMOVE(link, list_in);
871
872/* Close socket, if one has been allocated */
873 if (link->sockfd != -1)
874 {
875 la->sockCount--;
876 close(link->sockfd);
877 }
878
879/* Link-type dependent cleanup */
880 switch(link->link_type)
881 {
882 case LINK_ICMP:
883 la->icmpLinkCount--;
884 break;
885 case LINK_UDP:
886 la->udpLinkCount--;
887 break;
888 case LINK_TCP:
889 la->tcpLinkCount--;
890 free(link->data.tcp);
891 break;
892 case LINK_PPTP:
893 la->pptpLinkCount--;
894 break;
895 case LINK_FRAGMENT_ID:
896 la->fragmentIdLinkCount--;
897 break;
898 case LINK_FRAGMENT_PTR:
899 la->fragmentPtrLinkCount--;
900 if (link->data.frag_ptr != NULL)
901 free(link->data.frag_ptr);
902 break;
903 case LINK_ADDR:
904 break;
905 default:
906 la->protoLinkCount--;
907 break;
908 }
909
910/* Free memory */
911 free(link);
912
913/* Write statistics, if logging enabled */
914 if (la->packetAliasMode & PKT_ALIAS_LOG)
915 {
916 ShowAliasStats(la);
917 }
918}
919
920
921static struct alias_link *
922AddLink(struct libalias *la, struct in_addr src_addr,
923 struct in_addr dst_addr,
924 struct in_addr alias_addr,
925 u_short src_port,
926 u_short dst_port,
927 int alias_port_param, /* if less than zero, alias */
928 int link_type) /* port will be automatically */
929{ /* chosen. If greater than */
930 u_int start_point; /* zero, equal to alias port */
931 struct alias_link *link;
932
933 link = malloc(sizeof(struct alias_link));
934 if (link != NULL)
935 {
936 /* Basic initialization */
937 link->la = la;
938 link->src_addr = src_addr;
939 link->dst_addr = dst_addr;
940 link->alias_addr = alias_addr;
941 link->proxy_addr.s_addr = INADDR_ANY;
942 link->src_port = src_port;
943 link->dst_port = dst_port;
944 link->proxy_port = 0;
945 link->server = NULL;
946 link->link_type = link_type;
947 link->sockfd = -1;
948 link->flags = 0;
949 link->pflags = 0;
950 link->timestamp = la->timeStamp;
951
952 /* Expiration time */
953 switch (link_type)
954 {
955 case LINK_ICMP:
956 link->expire_time = ICMP_EXPIRE_TIME;
957 break;
958 case LINK_UDP:
959 link->expire_time = UDP_EXPIRE_TIME;
960 break;
961 case LINK_TCP:
962 link->expire_time = TCP_EXPIRE_INITIAL;
963 break;
964 case LINK_PPTP:
965 link->flags |= LINK_PERMANENT; /* no timeout. */
966 break;
967 case LINK_FRAGMENT_ID:
968 link->expire_time = FRAGMENT_ID_EXPIRE_TIME;
969 break;
970 case LINK_FRAGMENT_PTR:
971 link->expire_time = FRAGMENT_PTR_EXPIRE_TIME;
972 break;
973 case LINK_ADDR:
974 break;
975 default:
976 link->expire_time = PROTO_EXPIRE_TIME;
977 break;
978 }
979
980 /* Determine alias flags */
981 if (dst_addr.s_addr == INADDR_ANY)
982 link->flags |= LINK_UNKNOWN_DEST_ADDR;
983 if (dst_port == 0)
984 link->flags |= LINK_UNKNOWN_DEST_PORT;
985
986 /* Determine alias port */
987 if (GetNewPort(la, link, alias_port_param) != 0)
988 {
989 free(link);
990 return(NULL);
991 }
992
993 /* Link-type dependent initialization */
994 switch(link_type)
995 {
996 struct tcp_dat *aux_tcp;
997
998 case LINK_ICMP:
999 la->icmpLinkCount++;
1000 break;
1001 case LINK_UDP:
1002 la->udpLinkCount++;
1003 break;
1004 case LINK_TCP:
1005 aux_tcp = malloc(sizeof(struct tcp_dat));
1006 if (aux_tcp != NULL)
1007 {
1008 int i;
1009
1010 la->tcpLinkCount++;
1011 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
1012 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
1013 aux_tcp->state.index = 0;
1014 aux_tcp->state.ack_modified = 0;
1015 for (i=0; i<N_LINK_TCP_DATA; i++)
1016 aux_tcp->ack[i].active = 0;
1017 aux_tcp->fwhole = -1;
1018 link->data.tcp = aux_tcp;
1019 }
1020 else
1021 {
1022#ifdef DEBUG
1023 fprintf(stderr, "PacketAlias/AddLink: ");
1024 fprintf(stderr, " cannot allocate auxiliary TCP data\n");
1025#endif
1026 free(link);
1027 return (NULL);
1028 }
1029 break;
1030 case LINK_PPTP:
1031 la->pptpLinkCount++;
1032 break;
1033 case LINK_FRAGMENT_ID:
1034 la->fragmentIdLinkCount++;
1035 break;
1036 case LINK_FRAGMENT_PTR:
1037 la->fragmentPtrLinkCount++;
1038 break;
1039 case LINK_ADDR:
1040 break;
1041 default:
1042 la->protoLinkCount++;
1043 break;
1044 }
1045
1046 /* Set up pointers for output lookup table */
1047 start_point = StartPointOut(src_addr, dst_addr,
1048 src_port, dst_port, link_type);
1049 LIST_INSERT_HEAD(&la->linkTableOut[start_point], link, list_out);
1050
1051 /* Set up pointers for input lookup table */
1052 start_point = StartPointIn(alias_addr, link->alias_port, link_type);
1053 LIST_INSERT_HEAD(&la->linkTableIn[start_point], link, list_in);
1054 }
1055 else
1056 {
1057#ifdef DEBUG
1058 fprintf(stderr, "PacketAlias/AddLink(): ");
1059 fprintf(stderr, "malloc() call failed.\n");
1060#endif
1061 }
1062
1063 if (la->packetAliasMode & PKT_ALIAS_LOG)
1064 {
1065 ShowAliasStats(la);
1066 }
1067
1068 return(link);
1069}
1070
1071static struct alias_link *
1072ReLink(struct alias_link *old_link,
1073 struct in_addr src_addr,
1074 struct in_addr dst_addr,
1075 struct in_addr alias_addr,
1076 u_short src_port,
1077 u_short dst_port,
1078 int alias_port_param, /* if less than zero, alias */
1079 int link_type) /* port will be automatically */
1080{ /* chosen. If greater than */
1081 struct alias_link *new_link; /* zero, equal to alias port */
1082 struct libalias *la = old_link->la;
1083
1084 new_link = AddLink(la, src_addr, dst_addr, alias_addr,
1085 src_port, dst_port, alias_port_param,
1086 link_type);
1087#ifndef NO_FW_PUNCH
1088 if (new_link != NULL &&
1089 old_link->link_type == LINK_TCP &&
1090 old_link->data.tcp->fwhole > 0) {
1091 PunchFWHole(new_link);
1092 }
1093#endif
1094 DeleteLink(old_link);
1095 return new_link;
1096}
1097
1098static struct alias_link *
1099_FindLinkOut(struct libalias *la, struct in_addr src_addr,
1100 struct in_addr dst_addr,
1101 u_short src_port,
1102 u_short dst_port,
1103 int link_type,
1104 int replace_partial_links)
1105{
1106 u_int i;
1107 struct alias_link *link;
1108
1109 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
1110 LIST_FOREACH(link, &la->linkTableOut[i], list_out)
1111 {
1112 if (link->src_addr.s_addr == src_addr.s_addr
1113 && link->server == NULL
1114 && link->dst_addr.s_addr == dst_addr.s_addr
1115 && link->dst_port == dst_port
1116 && link->src_port == src_port
1117 && link->link_type == link_type)
1118 {
1119 link->timestamp = la->timeStamp;
1120 break;
1121 }
1122 }
1123
1124/* Search for partially specified links. */
1125 if (link == NULL && replace_partial_links)
1126 {
1127 if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY)
1128 {
1129 link = _FindLinkOut(la, src_addr, dst_addr, src_port, 0,
1130 link_type, 0);
1131 if (link == NULL)
1132 link = _FindLinkOut(la, src_addr, la->nullAddress, src_port,
1133 dst_port, link_type, 0);
1134 }
1135 if (link == NULL &&
1136 (dst_port != 0 || dst_addr.s_addr != INADDR_ANY))
1137 {
1138 link = _FindLinkOut(la, src_addr, la->nullAddress, src_port, 0,
1139 link_type, 0);
1140 }
1141 if (link != NULL)
1142 {
1143 link = ReLink(link,
1144 src_addr, dst_addr, link->alias_addr,
1145 src_port, dst_port, link->alias_port,
1146 link_type);
1147 }
1148 }
1149
1150 return(link);
1151}
1152
1153static struct alias_link *
1154FindLinkOut(struct libalias *la, struct in_addr src_addr,
1155 struct in_addr dst_addr,
1156 u_short src_port,
1157 u_short dst_port,
1158 int link_type,
1159 int replace_partial_links)
1160{
1161 struct alias_link *link;
1162
1163 link = _FindLinkOut(la, src_addr, dst_addr, src_port, dst_port,
1164 link_type, replace_partial_links);
1165
1166 if (link == NULL)
1167 {
1168 /* The following allows permanent links to be
1169 specified as using the default source address
1170 (i.e. device interface address) without knowing
1171 in advance what that address is. */
1172 if (la->aliasAddress.s_addr != INADDR_ANY &&
1173 src_addr.s_addr == la->aliasAddress.s_addr)
1174 {
1175 link = _FindLinkOut(la, la->nullAddress, dst_addr, src_port, dst_port,
1176 link_type, replace_partial_links);
1177 }
1178 }
1179
1180 return(link);
1181}
1182
1183
1184static struct alias_link *
1185_FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1186 struct in_addr alias_addr,
1187 u_short dst_port,
1188 u_short alias_port,
1189 int link_type,
1190 int replace_partial_links)
1191{
1192 int flags_in;
1193 u_int start_point;
1194 struct alias_link *link;
1195 struct alias_link *link_fully_specified;
1196 struct alias_link *link_unknown_all;
1197 struct alias_link *link_unknown_dst_addr;
1198 struct alias_link *link_unknown_dst_port;
1199
1200/* Initialize pointers */
1201 link_fully_specified = NULL;
1202 link_unknown_all = NULL;
1203 link_unknown_dst_addr = NULL;
1204 link_unknown_dst_port = NULL;
1205
1206/* If either the dest addr or port is unknown, the search
1207 loop will have to know about this. */
1208
1209 flags_in = 0;
1210 if (dst_addr.s_addr == INADDR_ANY)
1211 flags_in |= LINK_UNKNOWN_DEST_ADDR;
1212 if (dst_port == 0)
1213 flags_in |= LINK_UNKNOWN_DEST_PORT;
1214
1215/* Search loop */
1216 start_point = StartPointIn(alias_addr, alias_port, link_type);
1217 LIST_FOREACH(link, &la->linkTableIn[start_point], list_in)
1218 {
1219 int flags;
1220
1221 flags = flags_in | link->flags;
1222 if (!(flags & LINK_PARTIALLY_SPECIFIED))
1223 {
1224 if (link->alias_addr.s_addr == alias_addr.s_addr
1225 && link->alias_port == alias_port
1226 && link->dst_addr.s_addr == dst_addr.s_addr
1227 && link->dst_port == dst_port
1228 && link->link_type == link_type)
1229 {
1230 link_fully_specified = link;
1231 break;
1232 }
1233 }
1234 else if ((flags & LINK_UNKNOWN_DEST_ADDR)
1235 && (flags & LINK_UNKNOWN_DEST_PORT))
1236 {
1237 if (link->alias_addr.s_addr == alias_addr.s_addr
1238 && link->alias_port == alias_port
1239 && link->link_type == link_type)
1240 {
1241 if (link_unknown_all == NULL)
1242 link_unknown_all = link;
1243 }
1244 }
1245 else if (flags & LINK_UNKNOWN_DEST_ADDR)
1246 {
1247 if (link->alias_addr.s_addr == alias_addr.s_addr
1248 && link->alias_port == alias_port
1249 && link->link_type == link_type
1250 && link->dst_port == dst_port)
1251 {
1252 if (link_unknown_dst_addr == NULL)
1253 link_unknown_dst_addr = link;
1254 }
1255 }
1256 else if (flags & LINK_UNKNOWN_DEST_PORT)
1257 {
1258 if (link->alias_addr.s_addr == alias_addr.s_addr
1259 && link->alias_port == alias_port
1260 && link->link_type == link_type
1261 && link->dst_addr.s_addr == dst_addr.s_addr)
1262 {
1263 if (link_unknown_dst_port == NULL)
1264 link_unknown_dst_port = link;
1265 }
1266 }
1267 }
1268
1269
1270
1271 if (link_fully_specified != NULL)
1272 {
1273 link_fully_specified->timestamp = la->timeStamp;
1274 link = link_fully_specified;
1275 }
1276 else if (link_unknown_dst_port != NULL)
1277 link = link_unknown_dst_port;
1278 else if (link_unknown_dst_addr != NULL)
1279 link = link_unknown_dst_addr;
1280 else if (link_unknown_all != NULL)
1281 link = link_unknown_all;
1282 else
1283 return (NULL);
1284
1285 if (replace_partial_links &&
1286 (link->flags & LINK_PARTIALLY_SPECIFIED || link->server != NULL))
1287 {
1288 struct in_addr src_addr;
1289 u_short src_port;
1290
1291 if (link->server != NULL) { /* LSNAT link */
1292 src_addr = link->server->addr;
1293 src_port = link->server->port;
1294 link->server = link->server->next;
1295 } else {
1296 src_addr = link->src_addr;
1297 src_port = link->src_port;
1298 }
1299
1300 link = ReLink(link,
1301 src_addr, dst_addr, alias_addr,
1302 src_port, dst_port, alias_port,
1303 link_type);
1304 }
1305
1306 return (link);
1307}
1308
1309static struct alias_link *
1310FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1311 struct in_addr alias_addr,
1312 u_short dst_port,
1313 u_short alias_port,
1314 int link_type,
1315 int replace_partial_links)
1316{
1317 struct alias_link *link;
1318
1319 link = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port,
1320 link_type, replace_partial_links);
1321
1322 if (link == NULL)
1323 {
1324 /* The following allows permanent links to be
1325 specified as using the default aliasing address
1326 (i.e. device interface address) without knowing
1327 in advance what that address is. */
1328 if (la->aliasAddress.s_addr != INADDR_ANY &&
1329 alias_addr.s_addr == la->aliasAddress.s_addr)
1330 {
1331 link = _FindLinkIn(la, dst_addr, la->nullAddress, dst_port, alias_port,
1332 link_type, replace_partial_links);
1333 }
1334 }
1335
1336 return(link);
1337}
1338
1339
1340
1341
1342/* External routines for finding/adding links
1343
1344-- "external" means outside alias_db.c, but within alias*.c --

--- 8 unchanged lines hidden (view full) ---

1353 FindOriginalAddress(), FindAliasAddress()
1354
1355(prototypes in alias_local.h)
1356*/
1357
1358
1359struct alias_link *
1360FindIcmpIn(struct libalias *la, struct in_addr dst_addr,
1361 struct in_addr alias_addr,
1362 u_short id_alias,
1363 int create)
1364{
1365 struct alias_link *link;
1366
1367 link = FindLinkIn(la, dst_addr, alias_addr,
1368 NO_DEST_PORT, id_alias,
1369 LINK_ICMP, 0);
1370 if (link == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING))
1371 {
1372 struct in_addr target_addr;
1373
1374 target_addr = FindOriginalAddress(la, alias_addr);
1375 link = AddLink(la, target_addr, dst_addr, alias_addr,
1376 id_alias, NO_DEST_PORT, id_alias,
1377 LINK_ICMP);
1378 }
1379
1380 return (link);
1381}
1382
1383
1384struct alias_link *
1385FindIcmpOut(struct libalias *la, struct in_addr src_addr,
1386 struct in_addr dst_addr,
1387 u_short id,
1388 int create)
1389{
1390 struct alias_link * link;
1391
1392 link = FindLinkOut(la, src_addr, dst_addr,
1393 id, NO_DEST_PORT,
1394 LINK_ICMP, 0);
1395 if (link == NULL && create)
1396 {
1397 struct in_addr alias_addr;
1398
1399 alias_addr = FindAliasAddress(la, src_addr);
1400 link = AddLink(la, src_addr, dst_addr, alias_addr,
1401 id, NO_DEST_PORT, GET_ALIAS_ID,
1402 LINK_ICMP);
1403 }
1404
1405 return(link);
1406}
1407
1408
1409struct alias_link *
1410FindFragmentIn1(struct libalias *la, struct in_addr dst_addr,
1411 struct in_addr alias_addr,
1412 u_short ip_id)
1413{
1414 struct alias_link *link;
1415
1416 link = FindLinkIn(la, dst_addr, alias_addr,
1417 NO_DEST_PORT, ip_id,
1418 LINK_FRAGMENT_ID, 0);
1419
1420 if (link == NULL)
1421 {
1422 link = AddLink(la, la->nullAddress, dst_addr, alias_addr,
1423 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1424 LINK_FRAGMENT_ID);
1425 }
1426
1427 return(link);
1428}
1429
1430
1431struct alias_link *
1432FindFragmentIn2(struct libalias *la, struct in_addr dst_addr, /* Doesn't add a link if one */
1433 struct in_addr alias_addr, /* is not found. */
1434 u_short ip_id)
1435{
1436 return FindLinkIn(la, dst_addr, alias_addr,
1437 NO_DEST_PORT, ip_id,
1438 LINK_FRAGMENT_ID, 0);
1439}
1440
1441
1442struct alias_link *
1443AddFragmentPtrLink(struct libalias *la, struct in_addr dst_addr,
1444 u_short ip_id)
1445{
1446 return AddLink(la, la->nullAddress, dst_addr, la->nullAddress,
1447 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1448 LINK_FRAGMENT_PTR);
1449}
1450
1451
1452struct alias_link *
1453FindFragmentPtr(struct libalias *la, struct in_addr dst_addr,
1454 u_short ip_id)
1455{
1456 return FindLinkIn(la, dst_addr, la->nullAddress,
1457 NO_DEST_PORT, ip_id,
1458 LINK_FRAGMENT_PTR, 0);
1459}
1460
1461
1462struct alias_link *
1463FindProtoIn(struct libalias *la, struct in_addr dst_addr,
1464 struct in_addr alias_addr,
1465 u_char proto)
1466{
1467 struct alias_link *link;
1468
1469 link = FindLinkIn(la, dst_addr, alias_addr,
1470 NO_DEST_PORT, 0,
1471 proto, 1);
1472
1473 if (link == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING))
1474 {
1475 struct in_addr target_addr;
1476
1477 target_addr = FindOriginalAddress(la, alias_addr);
1478 link = AddLink(la, target_addr, dst_addr, alias_addr,
1479 NO_SRC_PORT, NO_DEST_PORT, 0,
1480 proto);
1481 }
1482
1483 return (link);
1484}
1485
1486
1487struct alias_link *
1488FindProtoOut(struct libalias *la, struct in_addr src_addr,
1489 struct in_addr dst_addr,
1490 u_char proto)
1491{
1492 struct alias_link *link;
1493
1494 link = FindLinkOut(la, src_addr, dst_addr,
1495 NO_SRC_PORT, NO_DEST_PORT,
1496 proto, 1);
1497
1498 if (link == NULL)
1499 {
1500 struct in_addr alias_addr;
1501
1502 alias_addr = FindAliasAddress(la, src_addr);
1503 link = AddLink(la, src_addr, dst_addr, alias_addr,
1504 NO_SRC_PORT, NO_DEST_PORT, 0,
1505 proto);
1506 }
1507
1508 return (link);
1509}
1510
1511
1512struct alias_link *
1513FindUdpTcpIn(struct libalias *la, struct in_addr dst_addr,
1514 struct in_addr alias_addr,
1515 u_short dst_port,
1516 u_short alias_port,
1517 u_char proto,
1518 int create)
1519{
1520 int link_type;
1521 struct alias_link *link;
1522
1523 switch (proto)
1524 {
1525 case IPPROTO_UDP:
1526 link_type = LINK_UDP;
1527 break;
1528 case IPPROTO_TCP:
1529 link_type = LINK_TCP;
1530 break;
1531 default:
1532 return NULL;
1533 break;
1534 }
1535
1536 link = FindLinkIn(la, dst_addr, alias_addr,
1537 dst_port, alias_port,
1538 link_type, create);
1539
1540 if (link == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING))
1541 {
1542 struct in_addr target_addr;
1543
1544 target_addr = FindOriginalAddress(la, alias_addr);
1545 link = AddLink(la, target_addr, dst_addr, alias_addr,
1546 alias_port, dst_port, alias_port,
1547 link_type);
1548 }
1549
1550 return(link);
1551}
1552
1553
1554struct alias_link *
1555FindUdpTcpOut(struct libalias *la, struct in_addr src_addr,
1556 struct in_addr dst_addr,
1557 u_short src_port,
1558 u_short dst_port,
1559 u_char proto,
1560 int create)
1561{
1562 int link_type;
1563 struct alias_link *link;
1564
1565 switch (proto)
1566 {
1567 case IPPROTO_UDP:
1568 link_type = LINK_UDP;
1569 break;
1570 case IPPROTO_TCP:
1571 link_type = LINK_TCP;
1572 break;
1573 default:
1574 return NULL;
1575 break;
1576 }
1577
1578 link = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create);
1579
1580 if (link == NULL && create)
1581 {
1582 struct in_addr alias_addr;
1583
1584 alias_addr = FindAliasAddress(la, src_addr);
1585 link = AddLink(la, src_addr, dst_addr, alias_addr,
1586 src_port, dst_port, GET_ALIAS_PORT,
1587 link_type);
1588 }
1589
1590 return(link);
1591}
1592
1593
1594struct alias_link *
1595AddPptp(struct libalias *la, struct in_addr src_addr,
1596 struct in_addr dst_addr,
1597 struct in_addr alias_addr,
1598 u_int16_t src_call_id)
1599{
1600 struct alias_link *link;
1601
1602 link = AddLink(la, src_addr, dst_addr, alias_addr,
1603 src_call_id, 0, GET_ALIAS_PORT,
1604 LINK_PPTP);
1605
1606 return (link);
1607}
1608
1609
1610struct alias_link *
1611FindPptpOutByCallId(struct libalias *la, struct in_addr src_addr,
1612 struct in_addr dst_addr,
1613 u_int16_t src_call_id)
1614{
1615 u_int i;
1616 struct alias_link *link;
1617
1618 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1619 LIST_FOREACH(link, &la->linkTableOut[i], list_out)
1620 if (link->link_type == LINK_PPTP &&
1621 link->src_addr.s_addr == src_addr.s_addr &&
1622 link->dst_addr.s_addr == dst_addr.s_addr &&
1623 link->src_port == src_call_id)
1624 break;
1625
1626 return (link);
1627}
1628
1629
1630struct alias_link *
1631FindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr,
1632 struct in_addr dst_addr,
1633 u_int16_t dst_call_id)
1634{
1635 u_int i;
1636 struct alias_link *link;
1637
1638 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1639 LIST_FOREACH(link, &la->linkTableOut[i], list_out)
1640 if (link->link_type == LINK_PPTP &&
1641 link->src_addr.s_addr == src_addr.s_addr &&
1642 link->dst_addr.s_addr == dst_addr.s_addr &&
1643 link->dst_port == dst_call_id)
1644 break;
1645
1646 return (link);
1647}
1648
1649
1650struct alias_link *
1651FindPptpInByCallId(struct libalias *la, struct in_addr dst_addr,
1652 struct in_addr alias_addr,
1653 u_int16_t dst_call_id)
1654{
1655 u_int i;
1656 struct alias_link *link;
1657
1658 i = StartPointIn(alias_addr, 0, LINK_PPTP);
1659 LIST_FOREACH(link, &la->linkTableIn[i], list_in)
1660 if (link->link_type == LINK_PPTP &&
1661 link->dst_addr.s_addr == dst_addr.s_addr &&
1662 link->alias_addr.s_addr == alias_addr.s_addr &&
1663 link->dst_port == dst_call_id)
1664 break;
1665
1666 return (link);
1667}
1668
1669
1670struct alias_link *
1671FindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr,
1672 struct in_addr alias_addr,
1673 u_int16_t alias_call_id)
1674{
1675 struct alias_link *link;
1676
1677 link = FindLinkIn(la, dst_addr, alias_addr,
1678 0/* any */, alias_call_id,
1679 LINK_PPTP, 0);
1680
1681
1682 return (link);
1683}
1684
1685
1686struct alias_link *
1687FindRtspOut(struct libalias *la, struct in_addr src_addr,
1688 struct in_addr dst_addr,
1689 u_short src_port,
1690 u_short alias_port,
1691 u_char proto)
1692{
1693 int link_type;
1694 struct alias_link *link;
1695
1696 switch (proto)
1697 {
1698 case IPPROTO_UDP:
1699 link_type = LINK_UDP;
1700 break;
1701 case IPPROTO_TCP:
1702 link_type = LINK_TCP;
1703 break;
1704 default:
1705 return NULL;
1706 break;
1707 }
1708
1709 link = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1);
1710
1711 if (link == NULL)
1712 {
1713 struct in_addr alias_addr;
1714
1715 alias_addr = FindAliasAddress(la, src_addr);
1716 link = AddLink(la, src_addr, dst_addr, alias_addr,
1717 src_port, 0, alias_port,
1718 link_type);
1719 }
1720
1721 return(link);
1722}
1723
1724
1725struct in_addr
1726FindOriginalAddress(struct libalias *la, struct in_addr alias_addr)
1727{
1728 struct alias_link *link;
1729
1730 link = FindLinkIn(la, la->nullAddress, alias_addr,
1731 0, 0, LINK_ADDR, 0);
1732 if (link == NULL)
1733 {
1734 la->newDefaultLink = 1;
1735 if (la->targetAddress.s_addr == INADDR_ANY)
1736 return alias_addr;
1737 else if (la->targetAddress.s_addr == INADDR_NONE)
1738 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1739 la->aliasAddress : alias_addr;
1740 else
1741 return la->targetAddress;
1742 }
1743 else
1744 {
1745 if (link->server != NULL) { /* LSNAT link */
1746 struct in_addr src_addr;
1747
1748 src_addr = link->server->addr;
1749 link->server = link->server->next;
1750 return (src_addr);
1751 } else if (link->src_addr.s_addr == INADDR_ANY)
1752 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1753 la->aliasAddress : alias_addr;
1754 else
1755 return link->src_addr;
1756 }
1757}
1758
1759
1760struct in_addr
1761FindAliasAddress(struct libalias *la, struct in_addr original_addr)
1762{
1763 struct alias_link *link;
1764
1765 link = FindLinkOut(la, original_addr, la->nullAddress,
1766 0, 0, LINK_ADDR, 0);
1767 if (link == NULL)
1768 {
1769 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1770 la->aliasAddress : original_addr;
1771 }
1772 else
1773 {
1774 if (link->alias_addr.s_addr == INADDR_ANY)
1775 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1776 la->aliasAddress : original_addr;
1777 else
1778 return link->alias_addr;
1779 }
1780}
1781
1782
1783/* External routines for getting or changing link data
1784 (external to alias_db.c, but internal to alias*.c)
1785
1786 SetFragmentData(), GetFragmentData()
1787 SetFragmentPtr(), GetFragmentPtr()

--- 5 unchanged lines hidden (view full) ---

1793 SetProtocolFlags(), GetProtocolFlags()
1794 SetDestCallId()
1795*/
1796
1797
1798void
1799SetFragmentAddr(struct alias_link *link, struct in_addr src_addr)
1800{
1801 link->data.frag_addr = src_addr;
1802}
1803
1804
1805void
1806GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr)
1807{
1808 *src_addr = link->data.frag_addr;
1809}
1810
1811
1812void
1813SetFragmentPtr(struct alias_link *link, char *fptr)
1814{
1815 link->data.frag_ptr = fptr;
1816}
1817
1818
1819void
1820GetFragmentPtr(struct alias_link *link, char **fptr)
1821{
1822 *fptr = link->data.frag_ptr;
1823}
1824
1825
1826void
1827SetStateIn(struct alias_link *link, int state)
1828{
1829 /* TCP input state */
1830 switch (state) {
1831 case ALIAS_TCP_STATE_DISCONNECTED:
1832 if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED)
1833 link->expire_time = TCP_EXPIRE_DEAD;
1834 else
1835 link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1836 break;
1837 case ALIAS_TCP_STATE_CONNECTED:
1838 if (link->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED)
1839 link->expire_time = TCP_EXPIRE_CONNECTED;
1840 break;
1841 default:
1842 abort();
1843 }
1844 link->data.tcp->state.in = state;
1845}
1846
1847
1848void
1849SetStateOut(struct alias_link *link, int state)
1850{
1851 /* TCP output state */
1852 switch (state) {
1853 case ALIAS_TCP_STATE_DISCONNECTED:
1854 if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED)
1855 link->expire_time = TCP_EXPIRE_DEAD;
1856 else
1857 link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1858 break;
1859 case ALIAS_TCP_STATE_CONNECTED:
1860 if (link->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED)
1861 link->expire_time = TCP_EXPIRE_CONNECTED;
1862 break;
1863 default:
1864 abort();
1865 }
1866 link->data.tcp->state.out = state;
1867}
1868
1869
1870int
1871GetStateIn(struct alias_link *link)
1872{
1873 /* TCP input state */
1874 return link->data.tcp->state.in;
1875}
1876
1877
1878int
1879GetStateOut(struct alias_link *link)
1880{
1881 /* TCP output state */
1882 return link->data.tcp->state.out;
1883}
1884
1885
1886struct in_addr
1887GetOriginalAddress(struct alias_link *link)
1888{
1889 if (link->src_addr.s_addr == INADDR_ANY)
1890 return link->la->aliasAddress;
1891 else
1892 return(link->src_addr);
1893}
1894
1895
1896struct in_addr
1897GetDestAddress(struct alias_link *link)
1898{
1899 return(link->dst_addr);
1900}
1901
1902
1903struct in_addr
1904GetAliasAddress(struct alias_link *link)
1905{
1906 if (link->alias_addr.s_addr == INADDR_ANY)
1907 return link->la->aliasAddress;
1908 else
1909 return link->alias_addr;
1910}
1911
1912
1913struct in_addr
1914GetDefaultAliasAddress(struct libalias *la)
1915{
1916 return la->aliasAddress;
1917}
1918
1919
1920void
1921SetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr)
1922{
1923 la->aliasAddress = alias_addr;
1924}
1925
1926
1927u_short
1928GetOriginalPort(struct alias_link *link)
1929{
1930 return(link->src_port);
1931}
1932
1933
1934u_short
1935GetAliasPort(struct alias_link *link)
1936{
1937 return(link->alias_port);
1938}
1939
1940#ifndef NO_FW_PUNCH
1941static u_short
1942GetDestPort(struct alias_link *link)
1943{
1944 return(link->dst_port);
1945}
1946#endif
1947
1948void
1949SetAckModified(struct alias_link *link)
1950{
1951/* Indicate that ACK numbers have been modified in a TCP connection */
1952 link->data.tcp->state.ack_modified = 1;
1953}
1954
1955
1956struct in_addr
1957GetProxyAddress(struct alias_link *link)
1958{
1959 return link->proxy_addr;
1960}
1961
1962
1963void
1964SetProxyAddress(struct alias_link *link, struct in_addr addr)
1965{
1966 link->proxy_addr = addr;
1967}
1968
1969
1970u_short
1971GetProxyPort(struct alias_link *link)
1972{
1973 return link->proxy_port;
1974}
1975
1976
1977void
1978SetProxyPort(struct alias_link *link, u_short port)
1979{
1980 link->proxy_port = port;
1981}
1982
1983
1984int
1985GetAckModified(struct alias_link *link)
1986{
1987/* See if ACK numbers have been modified */
1988 return link->data.tcp->state.ack_modified;
1989}
1990
1991
1992int
1993GetDeltaAckIn(struct ip *pip, struct alias_link *link)
1994{
1995/*
1996Find out how much the ACK number has been altered for an incoming
1997TCP packet. To do this, a circular list of ACK numbers where the TCP
1998packet size was altered is searched.
1999*/
2000
2001 int i;
2002 struct tcphdr *tc;
2003 int delta, ack_diff_min;
2004 u_long ack;
2005
2006 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
2007 ack = tc->th_ack;
2008
2009 delta = 0;
2010 ack_diff_min = -1;
2011 for (i=0; i<N_LINK_TCP_DATA; i++)
2012 {
2013 struct ack_data_record x;
2014
2015 x = link->data.tcp->ack[i];
2016 if (x.active == 1)
2017 {
2018 int ack_diff;
2019
2020 ack_diff = SeqDiff(x.ack_new, ack);
2021 if (ack_diff >= 0)
2022 {
2023 if (ack_diff_min >= 0)
2024 {
2025 if (ack_diff < ack_diff_min)
2026 {
2027 delta = x.delta;
2028 ack_diff_min = ack_diff;
2029 }
2030 }
2031 else
2032 {
2033 delta = x.delta;
2034 ack_diff_min = ack_diff;
2035 }
2036 }
2037 }
2038 }
2039 return (delta);
2040}
2041
2042
2043int
2044GetDeltaSeqOut(struct ip *pip, struct alias_link *link)
2045{
2046/*
2047Find out how much the sequence number has been altered for an outgoing
2048TCP packet. To do this, a circular list of ACK numbers where the TCP
2049packet size was altered is searched.
2050*/
2051
2052 int i;
2053 struct tcphdr *tc;
2054 int delta, seq_diff_min;
2055 u_long seq;
2056
2057 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
2058 seq = tc->th_seq;
2059
2060 delta = 0;
2061 seq_diff_min = -1;
2062 for (i=0; i<N_LINK_TCP_DATA; i++)
2063 {
2064 struct ack_data_record x;
2065
2066 x = link->data.tcp->ack[i];
2067 if (x.active == 1)
2068 {
2069 int seq_diff;
2070
2071 seq_diff = SeqDiff(x.ack_old, seq);
2072 if (seq_diff >= 0)
2073 {
2074 if (seq_diff_min >= 0)
2075 {
2076 if (seq_diff < seq_diff_min)
2077 {
2078 delta = x.delta;
2079 seq_diff_min = seq_diff;
2080 }
2081 }
2082 else
2083 {
2084 delta = x.delta;
2085 seq_diff_min = seq_diff;
2086 }
2087 }
2088 }
2089 }
2090 return (delta);
2091}
2092
2093
2094void
2095AddSeq(struct ip *pip, struct alias_link *link, int delta)
2096{
2097/*
2098When a TCP packet has been altered in length, save this
2099information in a circular list. If enough packets have
2100been altered, then this list will begin to overwrite itself.
2101*/
2102
2103 struct tcphdr *tc;
2104 struct ack_data_record x;
2105 int hlen, tlen, dlen;
2106 int i;
2107
2108 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
2109
2110 hlen = (pip->ip_hl + tc->th_off) << 2;
2111 tlen = ntohs(pip->ip_len);
2112 dlen = tlen - hlen;
2113
2114 x.ack_old = htonl(ntohl(tc->th_seq) + dlen);
2115 x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta);
2116 x.delta = delta;
2117 x.active = 1;
2118
2119 i = link->data.tcp->state.index;
2120 link->data.tcp->ack[i] = x;
2121
2122 i++;
2123 if (i == N_LINK_TCP_DATA)
2124 link->data.tcp->state.index = 0;
2125 else
2126 link->data.tcp->state.index = i;
2127}
2128
2129void
2130SetExpire(struct alias_link *link, int expire)
2131{
2132 if (expire == 0)
2133 {
2134 link->flags &= ~LINK_PERMANENT;
2135 DeleteLink(link);
2136 }
2137 else if (expire == -1)
2138 {
2139 link->flags |= LINK_PERMANENT;
2140 }
2141 else if (expire > 0)
2142 {
2143 link->expire_time = expire;
2144 }
2145 else
2146 {
2147#ifdef DEBUG
2148 fprintf(stderr, "PacketAlias/SetExpire(): ");
2149 fprintf(stderr, "error in expire parameter\n");
2150#endif
2151 }
2152}
2153
2154void
2155ClearCheckNewLink(struct libalias *la)
2156{
2157 la->newDefaultLink = 0;
2158}
2159
2160void
2161SetProtocolFlags(struct alias_link *link, int pflags)
2162{
2163
2164 link->pflags = pflags;;
2165}
2166
2167int
2168GetProtocolFlags(struct alias_link *link)
2169{
2170
2171 return (link->pflags);
2172}
2173
2174void
2175SetDestCallId(struct alias_link *link, u_int16_t cid)
2176{
2177 struct libalias *la = link->la;
2178
2179 la->deleteAllLinks = 1;
2180 link = ReLink(link, link->src_addr, link->dst_addr, link->alias_addr,
2181 link->src_port, cid, link->alias_port, link->link_type);
2182 la->deleteAllLinks = 0;
2183}
2184
2185
2186/* Miscellaneous Functions
2187
2188 HouseKeeping()
2189 InitPacketAliasLog()
2190 UninitPacketAliasLog()

--- 6 unchanged lines hidden (view full) ---

2197 every 60 seconds.
2198
2199 (prototype in alias_local.h)
2200*/
2201
2202void
2203HouseKeeping(struct libalias *la)
2204{
2205 int i, n, n100;
2206 struct timeval tv;
2207 struct timezone tz;
2208
2209 /*
2210 * Save system time (seconds) in global variable timeStamp for
2211 * use by other functions. This is done so as not to unnecessarily
2212 * waste timeline by making system calls.
2213 */
2214 gettimeofday(&tv, &tz);
2215 la->timeStamp = tv.tv_sec;
2216
2217 /* Compute number of spokes (output table link chains) to cover */
2218 n100 = LINK_TABLE_OUT_SIZE * 100 + la->houseKeepingResidual;
2219 n100 *= la->timeStamp - la->lastCleanupTime;
2220 n100 /= ALIAS_CLEANUP_INTERVAL_SECS;
2221
2222 n = n100/100;
2223
2224 /* Handle different cases */
2225 if (n > ALIAS_CLEANUP_MAX_SPOKES)
2226 {
2227 n = ALIAS_CLEANUP_MAX_SPOKES;
2228 la->lastCleanupTime = la->timeStamp;
2229 la->houseKeepingResidual = 0;
2230
2231 for (i=0; i<n; i++)
2232 IncrementalCleanup(la);
2233 }
2234 else if (n > 0)
2235 {
2236 la->lastCleanupTime = la->timeStamp;
2237 la->houseKeepingResidual = n100 - 100*n;
2238
2239 for (i=0; i<n; i++)
2240 IncrementalCleanup(la);
2241 }
2242 else if (n < 0)
2243 {
2244#ifdef DEBUG
2245 fprintf(stderr, "PacketAlias/HouseKeeping(): ");
2246 fprintf(stderr, "something unexpected in time values\n");
2247#endif
2248 la->lastCleanupTime = la->timeStamp;
2249 la->houseKeepingResidual = 0;
2250 }
2251}
2252
2253
2254/* Init the log file and enable logging */
2255static void
2256InitPacketAliasLog(struct libalias *la)
2257{
2258 if ((~la->packetAliasMode & PKT_ALIAS_LOG)
2259 && (la->monitorFile = fopen("/var/log/alias.log", "w")))
2260 {
2261 la->packetAliasMode |= PKT_ALIAS_LOG;
2262 fprintf(la->monitorFile,
2263 "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
2264 }
2265}
2266
2267
2268/* Close the log-file and disable logging. */
2269static void
2270UninitPacketAliasLog(struct libalias *la)
2271{
2272 if (la->monitorFile) {
2273 fclose(la->monitorFile);
2274 la->monitorFile = NULL;
2275 }
2276 la->packetAliasMode &= ~PKT_ALIAS_LOG;
2277}
2278
2279
2280
2281
2282
2283
2284/* Outside world interfaces

--- 12 unchanged lines hidden (view full) ---

2297 PacketAliasSetMode()
2298
2299(prototypes in alias.h)
2300*/
2301
2302/* Redirection from a specific public addr:port to a
2303 private addr:port */
2304struct alias_link *
2305LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port,
2306 struct in_addr dst_addr, u_short dst_port,
2307 struct in_addr alias_addr, u_short alias_port,
2308 u_char proto)
2309{
2310 int link_type;
2311 struct alias_link *link;
2312
2313 switch(proto)
2314 {
2315 case IPPROTO_UDP:
2316 link_type = LINK_UDP;
2317 break;
2318 case IPPROTO_TCP:
2319 link_type = LINK_TCP;
2320 break;
2321 default:
2322#ifdef DEBUG
2323 fprintf(stderr, "PacketAliasRedirectPort(): ");
2324 fprintf(stderr, "only TCP and UDP protocols allowed\n");
2325#endif
2326 return NULL;
2327 }
2328
2329 link = AddLink(la, src_addr, dst_addr, alias_addr,
2330 src_port, dst_port, alias_port,
2331 link_type);
2332
2333 if (link != NULL)
2334 {
2335 link->flags |= LINK_PERMANENT;
2336 }
2337#ifdef DEBUG
2338 else
2339 {
2340 fprintf(stderr, "PacketAliasRedirectPort(): "
2341 "call to AddLink() failed\n");
2342 }
2343#endif
2344
2345 return link;
2346}
2347
2348/* Add server to the pool of servers */
2349int
2350LibAliasAddServer(struct libalias *la, struct alias_link *link, struct in_addr addr, u_short port)
2351{
2352 struct server *server;
2353
2354 server = malloc(sizeof(struct server));
2355
2356 if (server != NULL) {
2357 struct server *head;
2358
2359 server->addr = addr;
2360 server->port = port;
2361
2362 head = link->server;
2363 if (head == NULL)
2364 server->next = server;
2365 else {
2366 struct server *s;
2367
2368 for (s = head; s->next != head; s = s->next);
2369 s->next = server;
2370 server->next = head;
2371 }
2372 link->server = server;
2373 return (0);
2374 } else
2375 return (-1);
2376}
2377
2378/* Redirect packets of a given IP protocol from a specific
2379 public address to a private address */
2380struct alias_link *
2381LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr,
2382 struct in_addr dst_addr,
2383 struct in_addr alias_addr,
2384 u_char proto)
2385{
2386 struct alias_link *link;
2387
2388 link = AddLink(la, src_addr, dst_addr, alias_addr,
2389 NO_SRC_PORT, NO_DEST_PORT, 0,
2390 proto);
2391
2392 if (link != NULL)
2393 {
2394 link->flags |= LINK_PERMANENT;
2395 }
2396#ifdef DEBUG
2397 else
2398 {
2399 fprintf(stderr, "PacketAliasRedirectProto(): "
2400 "call to AddLink() failed\n");
2401 }
2402#endif
2403
2404 return link;
2405}
2406
2407/* Static address translation */
2408struct alias_link *
2409LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr,
2410 struct in_addr alias_addr)
2411{
2412 struct alias_link *link;
2413
2414 link = AddLink(la, src_addr, la->nullAddress, alias_addr,
2415 0, 0, 0,
2416 LINK_ADDR);
2417
2418 if (link != NULL)
2419 {
2420 link->flags |= LINK_PERMANENT;
2421 }
2422#ifdef DEBUG
2423 else
2424 {
2425 fprintf(stderr, "PacketAliasRedirectAddr(): "
2426 "call to AddLink() failed\n");
2427 }
2428#endif
2429
2430 return link;
2431}
2432
2433
2434/* Mark the aliasing link dynamic */
2435int
2436LibAliasRedirectDynamic(struct libalias *la, struct alias_link *link)
2437{
2438
2439 if (link->flags & LINK_PARTIALLY_SPECIFIED)
2440 return (-1);
2441 else {
2442 link->flags &= ~LINK_PERMANENT;
2443 return (0);
2444 }
2445}
2446
2447
2448void
2449LibAliasRedirectDelete(struct libalias *la, struct alias_link *link)
2450{
2451/* This is a dangerous function to put in the API,
2452 because an invalid pointer can crash the program. */
2453
2454 la->deleteAllLinks = 1;
2455 DeleteLink(link);
2456 la->deleteAllLinks = 0;
2457}
2458
2459
2460void
2461LibAliasSetAddress(struct libalias *la, struct in_addr addr)
2462{
2463 if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2464 && la->aliasAddress.s_addr != addr.s_addr)
2465 CleanupAliasData(la);
2466
2467 la->aliasAddress = addr;
2468}
2469
2470
2471void
2472LibAliasSetTarget(struct libalias *la, struct in_addr target_addr)
2473{
2474 la->targetAddress = target_addr;
2475}
2476
2477static void
2478finishoff(void)
2479{
2480
2481 while(!LIST_EMPTY(&instancehead))
2482 LibAliasUninit(LIST_FIRST(&instancehead));
2483}
2484
2485struct libalias *
2486LibAliasInit(struct libalias *la)
2487{
2488 int i;
2489 struct timeval tv;
2490 struct timezone tz;
2491
2492 if (la == NULL)
2493 {
2494 la = calloc(sizeof *la, 1);
2495 if (la == NULL)
2496 return (la);
2497 if (LIST_EMPTY(&instancehead))
2498 atexit(finishoff);
2499 LIST_INSERT_HEAD(&instancehead, la, instancelist);
2500
2501 gettimeofday(&tv, &tz);
2502 la->timeStamp = tv.tv_sec;
2503 la->lastCleanupTime = tv.tv_sec;
2504 la->houseKeepingResidual = 0;
2505
2506 for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
2507 LIST_INIT(&la->linkTableOut[i]);
2508 for (i=0; i<LINK_TABLE_IN_SIZE; i++)
2509 LIST_INIT(&la->linkTableIn[i]);
2510
2511 }
2512 else
2513 {
2514 la->deleteAllLinks = 1;
2515 CleanupAliasData(la);
2516 la->deleteAllLinks = 0;
2517 }
2518
2519 la->aliasAddress.s_addr = INADDR_ANY;
2520 la->targetAddress.s_addr = INADDR_ANY;
2521
2522 la->icmpLinkCount = 0;
2523 la->udpLinkCount = 0;
2524 la->tcpLinkCount = 0;
2525 la->pptpLinkCount = 0;
2526 la->protoLinkCount = 0;
2527 la->fragmentIdLinkCount = 0;
2528 la->fragmentPtrLinkCount = 0;
2529 la->sockCount = 0;
2530
2531 la->cleanupIndex =0;
2532
2533 la->packetAliasMode = PKT_ALIAS_SAME_PORTS
2534 | PKT_ALIAS_USE_SOCKETS
2535 | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2536#ifndef NO_FW_PUNCH
2537 la->fireWallFD = -1;
2538#endif
2539 return (la);
2540}
2541
2542void
2543LibAliasUninit(struct libalias *la) {
2544 la->deleteAllLinks = 1;
2545 CleanupAliasData(la);
2546 la->deleteAllLinks = 0;
2547 UninitPacketAliasLog(la);
2548#ifndef NO_FW_PUNCH
2549 UninitPunchFW(la);
2550#endif
2551 LIST_REMOVE(la, instancelist);
2552 free(la);
2553}
2554
2555/* Change mode for some operations */
2556unsigned int
2557LibAliasSetMode(
2558 struct libalias *la,
2559 unsigned int flags, /* Which state to bring flags to */
2560 unsigned int mask /* Mask of which flags to affect (use 0 to do a
2561 probe for flag values) */
2562)
2563{
2564/* Enable logging? */
2565 if (flags & mask & PKT_ALIAS_LOG)
2566 {
2567 InitPacketAliasLog(la); /* Do the enable */
2568 } else
2569/* _Disable_ logging? */
2570 if (~flags & mask & PKT_ALIAS_LOG) {
2571 UninitPacketAliasLog(la);
2572 }
2573
2574#ifndef NO_FW_PUNCH
2575/* Start punching holes in the firewall? */
2576 if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2577 InitPunchFW(la);
2578 } else
2579/* Stop punching holes in the firewall? */
2580 if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2581 UninitPunchFW(la);
2582 }
2583#endif
2584
2585/* Other flags can be set/cleared without special action */
2586 la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask);
2587 return la->packetAliasMode;
2588}
2589
2590
2591int
2592LibAliasCheckNewLink(struct libalias *la)
2593{
2594 return la->newDefaultLink;
2595}
2596
2597
2598#ifndef NO_FW_PUNCH
2599
2600/*****************
2601 Code to support firewall punching. This shouldn't really be in this
2602 file, but making variables global is evil too.
2603 ****************/
2604
2605#ifndef IPFW2
2606#define IPFW2 1 /* use new ipfw code */
2607#endif
2608
2609/* Firewall include files */
2610#include <net/if.h>
2611#include <netinet/ip_fw.h>
2612#include <string.h>
2613#include <err.h>
2614
2615#if IPFW2 /* support for new firewall code */
2616/*
2617 * helper function, updates the pointer to cmd with the length
2618 * of the current command, and also cleans up the first word of
2619 * the new command in case it has been clobbered before.
2620 */
2621static ipfw_insn *
2622next_cmd(ipfw_insn *cmd)
2623{
2624 cmd += F_LEN(cmd);
2625 bzero(cmd, sizeof(*cmd));
2626 return cmd;
2627}
2628
2629/*
2630 * A function to fill simple commands of size 1.
2631 * Existing flags are preserved.
2632 */
2633static ipfw_insn *
2634fill_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, int size,
2635 int flags, u_int16_t arg)
2636{
2637 cmd->opcode = opcode;
2638 cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK);
2639 cmd->arg1 = arg;
2640 return next_cmd(cmd);
2641}
2642
2643static ipfw_insn *
2644fill_ip(ipfw_insn *cmd1, enum ipfw_opcodes opcode, u_int32_t addr)
2645{
2646 ipfw_insn_ip *cmd = (ipfw_insn_ip *)cmd1;
2647
2648 cmd->addr.s_addr = addr;
2649 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0);
2650}
2651
2652static ipfw_insn *
2653fill_one_port(ipfw_insn *cmd1, enum ipfw_opcodes opcode, u_int16_t port)
2654{
2655 ipfw_insn_u16 *cmd = (ipfw_insn_u16 *)cmd1;
2656
2657 cmd->ports[0] = cmd->ports[1] = port;
2658 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0);
2659}
2660
2661static int
2662fill_rule(void *buf, int bufsize, int rulenum,
2663 enum ipfw_opcodes action, int proto,
2664 struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp)
2665{
2666 struct ip_fw *rule = (struct ip_fw *)buf;
2667 ipfw_insn *cmd = (ipfw_insn *)rule->cmd;
2668
2669 bzero(buf, bufsize);
2670 rule->rulenum = rulenum;
2671
2672 cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto);
2673 cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr);
2674 cmd = fill_one_port(cmd, O_IP_SRCPORT, sp);
2675 cmd = fill_ip(cmd, O_IP_DST, da.s_addr);
2676 cmd = fill_one_port(cmd, O_IP_DSTPORT, dp);
2677
2678 rule->act_ofs = (u_int32_t *)cmd - (u_int32_t *)rule->cmd;
2679 cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0);
2680
2681 rule->cmd_len = (u_int32_t *)cmd - (u_int32_t *)rule->cmd;
2682
2683 return ((char *)cmd - (char *)buf);
2684}
2685#endif /* IPFW2 */
2686
2687static void ClearAllFWHoles(struct libalias *la);
2688
2689
2690#define fw_setfield(la, field, num) \
2691do { \
2692 (field)[(num) - la->fireWallBaseNum] = 1; \
2693} /*lint -save -e717 */ while(0) /*lint -restore */
2694
2695#define fw_clrfield(la, field, num) \
2696do { \
2697 (field)[(num) - la->fireWallBaseNum] = 0; \
2698} /*lint -save -e717 */ while(0) /*lint -restore */
2699
2700#define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum])
2701
2702static void
2703InitPunchFW(struct libalias *la)
2704{
2705
2706 la->fireWallField = malloc(la->fireWallNumNums);
2707 if (la->fireWallField) {
2708 memset(la->fireWallField, 0, la->fireWallNumNums);
2709 if (la->fireWallFD < 0) {
2710 la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2711 }
2712 ClearAllFWHoles(la);
2713 la->fireWallActiveNum = la->fireWallBaseNum;
2714 }
2715}
2716
2717static void
2718UninitPunchFW(struct libalias *la)
2719{
2720 ClearAllFWHoles(la);
2721 if (la->fireWallFD >= 0)
2722 close(la->fireWallFD);
2723 la->fireWallFD = -1;
2724 if (la->fireWallField)
2725 free(la->fireWallField);
2726 la->fireWallField = NULL;
2727 la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2728}
2729
2730/* Make a certain link go through the firewall */
2731void
2732PunchFWHole(struct alias_link *link)
2733{
2734 struct libalias *la;
2735 int r; /* Result code */
2736 struct ip_fw rule; /* On-the-fly built rule */
2737 int fwhole; /* Where to punch hole */
2738
2739 la = link->la;
2740
2741/* Don't do anything unless we are asked to */
2742 if ( !(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2743 la->fireWallFD < 0 ||
2744 link->link_type != LINK_TCP)
2745 return;
2746
2747 memset(&rule, 0, sizeof rule);
2748
2749/** Build rule **/
2750
2751 /* Find empty slot */
2752 for (fwhole = la->fireWallActiveNum;
2753 fwhole < la->fireWallBaseNum + la->fireWallNumNums &&
2754 fw_tstfield(la, la->fireWallField, fwhole);
2755 fwhole++)
2756 ;
2757 if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) {
2758 for (fwhole = la->fireWallBaseNum;
2759 fwhole < la->fireWallActiveNum &&
2760 fw_tstfield(la, la->fireWallField, fwhole);
2761 fwhole++)
2762 ;
2763 if (fwhole == la->fireWallActiveNum) {
2764 /* No rule point empty - we can't punch more holes. */
2765 la->fireWallActiveNum = la->fireWallBaseNum;
2766#ifdef DEBUG
2767 fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2768#endif
2769 return;
2770 }
2771 }
2772 /* Start next search at next position */
2773 la->fireWallActiveNum = fwhole+1;
2774
2775 /*
2776 * generate two rules of the form
2777 *
2778 * add fwhole accept tcp from OAddr OPort to DAddr DPort
2779 * add fwhole accept tcp from DAddr DPort to OAddr OPort
2780 */
2781#if IPFW2
2782 if (GetOriginalPort(link) != 0 && GetDestPort(link) != 0) {
2783 u_int32_t rulebuf[255];
2784 int i;
2785
2786 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2787 O_ACCEPT, IPPROTO_TCP,
2788 GetOriginalAddress(link), ntohs(GetOriginalPort(link)),
2789 GetDestAddress(link), ntohs(GetDestPort(link)) );
2790 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2791 if (r)
2792 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2793
2794 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2795 O_ACCEPT, IPPROTO_TCP,
2796 GetDestAddress(link), ntohs(GetDestPort(link)),
2797 GetOriginalAddress(link), ntohs(GetOriginalPort(link)) );
2798 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2799 if (r)
2800 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2801 }
2802#else /* !IPFW2, old code to generate ipfw rule */
2803
2804 /* Build generic part of the two rules */
2805 rule.fw_number = fwhole;
2806 IP_FW_SETNSRCP(&rule, 1); /* Number of source ports. */
2807 IP_FW_SETNDSTP(&rule, 1); /* Number of destination ports. */
2808 rule.fw_flg = IP_FW_F_ACCEPT | IP_FW_F_IN | IP_FW_F_OUT;
2809 rule.fw_prot = IPPROTO_TCP;
2810 rule.fw_smsk.s_addr = INADDR_BROADCAST;
2811 rule.fw_dmsk.s_addr = INADDR_BROADCAST;
2812
2813 /* Build and apply specific part of the rules */
2814 rule.fw_src = GetOriginalAddress(link);
2815 rule.fw_dst = GetDestAddress(link);
2816 rule.fw_uar.fw_pts[0] = ntohs(GetOriginalPort(link));
2817 rule.fw_uar.fw_pts[1] = ntohs(GetDestPort(link));
2818
2819 /* Skip non-bound links - XXX should not be strictly necessary,
2820 but seems to leave hole if not done. Leak of non-bound links?
2821 (Code should be left even if the problem is fixed - it is a
2822 clear optimization) */
2823 if (rule.fw_uar.fw_pts[0] != 0 && rule.fw_uar.fw_pts[1] != 0) {
2824 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
2825#ifdef DEBUG
2826 if (r)
2827 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2828#endif
2829 rule.fw_src = GetDestAddress(link);
2830 rule.fw_dst = GetOriginalAddress(link);
2831 rule.fw_uar.fw_pts[0] = ntohs(GetDestPort(link));
2832 rule.fw_uar.fw_pts[1] = ntohs(GetOriginalPort(link));
2833 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
2834#ifdef DEBUG
2835 if (r)
2836 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2837#endif
2838 }
2839#endif /* !IPFW2 */
2840/* Indicate hole applied */
2841 link->data.tcp->fwhole = fwhole;
2842 fw_setfield(la, la->fireWallField, fwhole);
2843}
2844
2845/* Remove a hole in a firewall associated with a particular alias
2846 link. Calling this too often is harmless. */
2847static void
2848ClearFWHole(struct alias_link *link)
2849{
2850
2851 struct libalias *la;
2852
2853 la = link->la;
2854 if (link->link_type == LINK_TCP) {
2855 int fwhole = link->data.tcp->fwhole; /* Where is the firewall hole? */
2856 struct ip_fw rule;
2857
2858 if (fwhole < 0)
2859 return;
2860
2861 memset(&rule, 0, sizeof rule); /* useless for ipfw2 */
2862#if IPFW2
2863 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL,
2864 &fwhole, sizeof fwhole))
2865 ;
2866#else /* !IPFW2 */
2867 rule.fw_number = fwhole;
2868 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL,
2869 &rule, sizeof rule))
2870 ;
2871#endif /* !IPFW2 */
2872 fw_clrfield(la, la->fireWallField, fwhole);
2873 link->data.tcp->fwhole = -1;
2874 }
2875}
2876
2877/* Clear out the entire range dedicated to firewall holes. */
2878static void
2879ClearAllFWHoles(struct libalias *la) {
2880 struct ip_fw rule; /* On-the-fly built rule */
2881 int i;
2882
2883 if (la->fireWallFD < 0)
2884 return;
2885
2886 memset(&rule, 0, sizeof rule);
2887 for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) {
2888#if IPFW2
2889 int r = i;
2890 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r))
2891 ;
2892#else /* !IPFW2 */
2893 rule.fw_number = i;
2894 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule))
2895 ;
2896#endif /* !IPFW2 */
2897 }
2898 /* XXX: third arg correct here ? /phk */
2899 memset(la->fireWallField, 0, la->fireWallNumNums);
2900}
2901#endif
2902
2903void
2904LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num) {
2905#ifndef NO_FW_PUNCH
2906 la->fireWallBaseNum = base;
2907 la->fireWallNumNums = num;
2908#endif
2909}
2910
2911void
2912LibAliasSetSkinnyPort(struct libalias *la, unsigned int port) {
2913 la->skinnyPort = port;
2914}