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

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

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

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

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

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

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

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

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

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

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

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

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

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

1281 FindOriginalAddress(), FindAliasAddress()
1282
1283(prototypes in alias_local.h)
1284*/
1285
1286
1287struct alias_link *
1288FindIcmpIn(struct libalias *la, struct in_addr dst_addr,
1289 struct in_addr alias_addr,
1290 u_short id_alias,
1291 int create)
1292{
1293 struct alias_link *link;
1294
1295 link = FindLinkIn(la, dst_addr, alias_addr,
1296 NO_DEST_PORT, id_alias,
1297 LINK_ICMP, 0);
1298 if (link == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1299 struct in_addr target_addr;
1300
1301 target_addr = FindOriginalAddress(la, alias_addr);
1302 link = AddLink(la, target_addr, dst_addr, alias_addr,
1303 id_alias, NO_DEST_PORT, id_alias,
1304 LINK_ICMP);
1305 }
1306 return (link);
1307}
1308
1309
1310struct alias_link *
1311FindIcmpOut(struct libalias *la, struct in_addr src_addr,
1312 struct in_addr dst_addr,
1313 u_short id,
1314 int create)
1315{
1316 struct alias_link *link;
1317
1318 link = FindLinkOut(la, src_addr, dst_addr,
1319 id, NO_DEST_PORT,
1320 LINK_ICMP, 0);
1321 if (link == NULL && create) {
1322 struct in_addr alias_addr;
1323
1324 alias_addr = FindAliasAddress(la, src_addr);
1325 link = AddLink(la, src_addr, dst_addr, alias_addr,
1326 id, NO_DEST_PORT, GET_ALIAS_ID,
1327 LINK_ICMP);
1328 }
1329 return (link);
1330}
1331
1332
1333struct alias_link *
1334FindFragmentIn1(struct libalias *la, struct in_addr dst_addr,
1335 struct in_addr alias_addr,
1336 u_short ip_id)
1337{
1338 struct alias_link *link;
1339
1340 link = FindLinkIn(la, dst_addr, alias_addr,
1341 NO_DEST_PORT, ip_id,
1342 LINK_FRAGMENT_ID, 0);
1343
1344 if (link == NULL) {
1345 link = AddLink(la, la->nullAddress, dst_addr, alias_addr,
1346 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1347 LINK_FRAGMENT_ID);
1348 }
1349 return (link);
1350}
1351
1352
1353struct alias_link *
1354FindFragmentIn2(struct libalias *la, struct in_addr dst_addr, /* Doesn't add a link if
1355 * one */
1356 struct in_addr alias_addr, /* is not found. */
1357 u_short ip_id)
1358{
1359 return FindLinkIn(la, dst_addr, alias_addr,
1360 NO_DEST_PORT, ip_id,
1361 LINK_FRAGMENT_ID, 0);
1362}
1363
1364
1365struct alias_link *
1366AddFragmentPtrLink(struct libalias *la, struct in_addr dst_addr,
1367 u_short ip_id)
1368{
1369 return AddLink(la, la->nullAddress, dst_addr, la->nullAddress,
1370 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1371 LINK_FRAGMENT_PTR);
1372}
1373
1374
1375struct alias_link *
1376FindFragmentPtr(struct libalias *la, struct in_addr dst_addr,
1377 u_short ip_id)
1378{
1379 return FindLinkIn(la, dst_addr, la->nullAddress,
1380 NO_DEST_PORT, ip_id,
1381 LINK_FRAGMENT_PTR, 0);
1382}
1383
1384
1385struct alias_link *
1386FindProtoIn(struct libalias *la, struct in_addr dst_addr,
1387 struct in_addr alias_addr,
1388 u_char proto)
1389{
1390 struct alias_link *link;
1391
1392 link = FindLinkIn(la, dst_addr, alias_addr,
1393 NO_DEST_PORT, 0,
1394 proto, 1);
1395
1396 if (link == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1397 struct in_addr target_addr;
1398
1399 target_addr = FindOriginalAddress(la, alias_addr);
1400 link = AddLink(la, target_addr, dst_addr, alias_addr,
1401 NO_SRC_PORT, NO_DEST_PORT, 0,
1402 proto);
1403 }
1404 return (link);
1405}
1406
1407
1408struct alias_link *
1409FindProtoOut(struct libalias *la, struct in_addr src_addr,
1410 struct in_addr dst_addr,
1411 u_char proto)
1412{
1413 struct alias_link *link;
1414
1415 link = FindLinkOut(la, src_addr, dst_addr,
1416 NO_SRC_PORT, NO_DEST_PORT,
1417 proto, 1);
1418
1419 if (link == NULL) {
1420 struct in_addr alias_addr;
1421
1422 alias_addr = FindAliasAddress(la, src_addr);
1423 link = AddLink(la, src_addr, dst_addr, alias_addr,
1424 NO_SRC_PORT, NO_DEST_PORT, 0,
1425 proto);
1426 }
1427 return (link);
1428}
1429
1430
1431struct alias_link *
1432FindUdpTcpIn(struct libalias *la, struct in_addr dst_addr,
1433 struct in_addr alias_addr,
1434 u_short dst_port,
1435 u_short alias_port,
1436 u_char proto,
1437 int create)
1438{
1439 int link_type;
1440 struct alias_link *link;
1441
1442 switch (proto) {
1443 case IPPROTO_UDP:
1444 link_type = LINK_UDP;
1445 break;
1446 case IPPROTO_TCP:
1447 link_type = LINK_TCP;
1448 break;
1449 default:
1450 return NULL;
1451 break;
1452 }
1453
1454 link = FindLinkIn(la, dst_addr, alias_addr,
1455 dst_port, alias_port,
1456 link_type, create);
1457
1458 if (link == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1459 struct in_addr target_addr;
1460
1461 target_addr = FindOriginalAddress(la, alias_addr);
1462 link = AddLink(la, target_addr, dst_addr, alias_addr,
1463 alias_port, dst_port, alias_port,
1464 link_type);
1465 }
1466 return (link);
1467}
1468
1469
1470struct alias_link *
1471FindUdpTcpOut(struct libalias *la, struct in_addr src_addr,
1472 struct in_addr dst_addr,
1473 u_short src_port,
1474 u_short dst_port,
1475 u_char proto,
1476 int create)
1477{
1478 int link_type;
1479 struct alias_link *link;
1480
1481 switch (proto) {
1482 case IPPROTO_UDP:
1483 link_type = LINK_UDP;
1484 break;
1485 case IPPROTO_TCP:
1486 link_type = LINK_TCP;
1487 break;
1488 default:
1489 return NULL;
1490 break;
1491 }
1492
1493 link = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create);
1494
1495 if (link == NULL && create) {
1496 struct in_addr alias_addr;
1497
1498 alias_addr = FindAliasAddress(la, src_addr);
1499 link = AddLink(la, src_addr, dst_addr, alias_addr,
1500 src_port, dst_port, GET_ALIAS_PORT,
1501 link_type);
1502 }
1503 return (link);
1504}
1505
1506
1507struct alias_link *
1508AddPptp(struct libalias *la, struct in_addr src_addr,
1509 struct in_addr dst_addr,
1510 struct in_addr alias_addr,
1511 u_int16_t src_call_id)
1512{
1513 struct alias_link *link;
1514
1515 link = AddLink(la, src_addr, dst_addr, alias_addr,
1516 src_call_id, 0, GET_ALIAS_PORT,
1517 LINK_PPTP);
1518
1519 return (link);
1520}
1521
1522
1523struct alias_link *
1524FindPptpOutByCallId(struct libalias *la, struct in_addr src_addr,
1525 struct in_addr dst_addr,
1526 u_int16_t src_call_id)
1527{
1528 u_int i;
1529 struct alias_link *link;
1530
1531 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1532 LIST_FOREACH(link, &la->linkTableOut[i], list_out)
1533 if (link->link_type == LINK_PPTP &&
1534 link->src_addr.s_addr == src_addr.s_addr &&
1535 link->dst_addr.s_addr == dst_addr.s_addr &&
1536 link->src_port == src_call_id)
1537 break;
1538
1539 return (link);
1540}
1541
1542
1543struct alias_link *
1544FindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr,
1545 struct in_addr dst_addr,
1546 u_int16_t dst_call_id)
1547{
1548 u_int i;
1549 struct alias_link *link;
1550
1551 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1552 LIST_FOREACH(link, &la->linkTableOut[i], list_out)
1553 if (link->link_type == LINK_PPTP &&
1554 link->src_addr.s_addr == src_addr.s_addr &&
1555 link->dst_addr.s_addr == dst_addr.s_addr &&
1556 link->dst_port == dst_call_id)
1557 break;
1558
1559 return (link);
1560}
1561
1562
1563struct alias_link *
1564FindPptpInByCallId(struct libalias *la, struct in_addr dst_addr,
1565 struct in_addr alias_addr,
1566 u_int16_t dst_call_id)
1567{
1568 u_int i;
1569 struct alias_link *link;
1570
1571 i = StartPointIn(alias_addr, 0, LINK_PPTP);
1572 LIST_FOREACH(link, &la->linkTableIn[i], list_in)
1573 if (link->link_type == LINK_PPTP &&
1574 link->dst_addr.s_addr == dst_addr.s_addr &&
1575 link->alias_addr.s_addr == alias_addr.s_addr &&
1576 link->dst_port == dst_call_id)
1577 break;
1578
1579 return (link);
1580}
1581
1582
1583struct alias_link *
1584FindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr,
1585 struct in_addr alias_addr,
1586 u_int16_t alias_call_id)
1587{
1588 struct alias_link *link;
1589
1590 link = FindLinkIn(la, dst_addr, alias_addr,
1591 0 /* any */ , alias_call_id,
1592 LINK_PPTP, 0);
1593
1594
1595 return (link);
1596}
1597
1598
1599struct alias_link *
1600FindRtspOut(struct libalias *la, struct in_addr src_addr,
1601 struct in_addr dst_addr,
1602 u_short src_port,
1603 u_short alias_port,
1604 u_char proto)
1605{
1606 int link_type;
1607 struct alias_link *link;
1608
1609 switch (proto) {
1610 case IPPROTO_UDP:
1611 link_type = LINK_UDP;
1612 break;
1613 case IPPROTO_TCP:
1614 link_type = LINK_TCP;
1615 break;
1616 default:
1617 return NULL;
1618 break;
1619 }
1620
1621 link = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1);
1622
1623 if (link == NULL) {
1624 struct in_addr alias_addr;
1625
1626 alias_addr = FindAliasAddress(la, src_addr);
1627 link = AddLink(la, src_addr, dst_addr, alias_addr,
1628 src_port, 0, alias_port,
1629 link_type);
1630 }
1631 return (link);
1632}
1633
1634
1635struct in_addr
1636FindOriginalAddress(struct libalias *la, struct in_addr alias_addr)
1637{
1638 struct alias_link *link;
1639
1640 link = FindLinkIn(la, la->nullAddress, alias_addr,
1641 0, 0, LINK_ADDR, 0);
1642 if (link == NULL) {
1643 la->newDefaultLink = 1;
1644 if (la->targetAddress.s_addr == INADDR_ANY)
1645 return alias_addr;
1646 else if (la->targetAddress.s_addr == INADDR_NONE)
1647 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1648 la->aliasAddress : alias_addr;
1649 else
1650 return la->targetAddress;
1651 } else {
1652 if (link->server != NULL) { /* LSNAT link */
1653 struct in_addr src_addr;
1654
1655 src_addr = link->server->addr;
1656 link->server = link->server->next;
1657 return (src_addr);
1658 } else if (link->src_addr.s_addr == INADDR_ANY)
1659 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1660 la->aliasAddress : alias_addr;
1661 else
1662 return link->src_addr;
1663 }
1664}
1665
1666
1667struct in_addr
1668FindAliasAddress(struct libalias *la, struct in_addr original_addr)
1669{
1670 struct alias_link *link;
1671
1672 link = FindLinkOut(la, original_addr, la->nullAddress,
1673 0, 0, LINK_ADDR, 0);
1674 if (link == NULL) {
1675 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1676 la->aliasAddress : original_addr;
1677 } else {
1678 if (link->alias_addr.s_addr == INADDR_ANY)
1679 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1680 la->aliasAddress : original_addr;
1681 else
1682 return link->alias_addr;
1683 }
1684}
1685
1686
1687/* External routines for getting or changing link data
1688 (external to alias_db.c, but internal to alias*.c)
1689
1690 SetFragmentData(), GetFragmentData()
1691 SetFragmentPtr(), GetFragmentPtr()

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

1697 SetProtocolFlags(), GetProtocolFlags()
1698 SetDestCallId()
1699*/
1700
1701
1702void
1703SetFragmentAddr(struct alias_link *link, struct in_addr src_addr)
1704{
1705 link->data.frag_addr = src_addr;
1706}
1707
1708
1709void
1710GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr)
1711{
1712 *src_addr = link->data.frag_addr;
1713}
1714
1715
1716void
1717SetFragmentPtr(struct alias_link *link, char *fptr)
1718{
1719 link->data.frag_ptr = fptr;
1720}
1721
1722
1723void
1724GetFragmentPtr(struct alias_link *link, char **fptr)
1725{
1726 *fptr = link->data.frag_ptr;
1727}
1728
1729
1730void
1731SetStateIn(struct alias_link *link, int state)
1732{
1733 /* TCP input state */
1734 switch (state) {
1735 case ALIAS_TCP_STATE_DISCONNECTED:
1736 if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED)
1737 link->expire_time = TCP_EXPIRE_DEAD;
1738 else
1739 link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1740 break;
1741 case ALIAS_TCP_STATE_CONNECTED:
1742 if (link->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED)
1743 link->expire_time = TCP_EXPIRE_CONNECTED;
1744 break;
1745 default:
1746 abort();
1747 }
1748 link->data.tcp->state.in = state;
1749}
1750
1751
1752void
1753SetStateOut(struct alias_link *link, int state)
1754{
1755 /* TCP output state */
1756 switch (state) {
1757 case ALIAS_TCP_STATE_DISCONNECTED:
1758 if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED)
1759 link->expire_time = TCP_EXPIRE_DEAD;
1760 else
1761 link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1762 break;
1763 case ALIAS_TCP_STATE_CONNECTED:
1764 if (link->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED)
1765 link->expire_time = TCP_EXPIRE_CONNECTED;
1766 break;
1767 default:
1768 abort();
1769 }
1770 link->data.tcp->state.out = state;
1771}
1772
1773
1774int
1775GetStateIn(struct alias_link *link)
1776{
1777 /* TCP input state */
1778 return link->data.tcp->state.in;
1779}
1780
1781
1782int
1783GetStateOut(struct alias_link *link)
1784{
1785 /* TCP output state */
1786 return link->data.tcp->state.out;
1787}
1788
1789
1790struct in_addr
1791GetOriginalAddress(struct alias_link *link)
1792{
1793 if (link->src_addr.s_addr == INADDR_ANY)
1794 return link->la->aliasAddress;
1795 else
1796 return (link->src_addr);
1797}
1798
1799
1800struct in_addr
1801GetDestAddress(struct alias_link *link)
1802{
1803 return (link->dst_addr);
1804}
1805
1806
1807struct in_addr
1808GetAliasAddress(struct alias_link *link)
1809{
1810 if (link->alias_addr.s_addr == INADDR_ANY)
1811 return link->la->aliasAddress;
1812 else
1813 return link->alias_addr;
1814}
1815
1816
1817struct in_addr
1818GetDefaultAliasAddress(struct libalias *la)
1819{
1820 return la->aliasAddress;
1821}
1822
1823
1824void
1825SetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr)
1826{
1827 la->aliasAddress = alias_addr;
1828}
1829
1830
1831u_short
1832GetOriginalPort(struct alias_link *link)
1833{
1834 return (link->src_port);
1835}
1836
1837
1838u_short
1839GetAliasPort(struct alias_link *link)
1840{
1841 return (link->alias_port);
1842}
1843
1844#ifndef NO_FW_PUNCH
1845static u_short
1846GetDestPort(struct alias_link *link)
1847{
1848 return (link->dst_port);
1849}
1850
1851#endif
1852
1853void
1854SetAckModified(struct alias_link *link)
1855{
1856/* Indicate that ACK numbers have been modified in a TCP connection */
1857 link->data.tcp->state.ack_modified = 1;
1858}
1859
1860
1861struct in_addr
1862GetProxyAddress(struct alias_link *link)
1863{
1864 return link->proxy_addr;
1865}
1866
1867
1868void
1869SetProxyAddress(struct alias_link *link, struct in_addr addr)
1870{
1871 link->proxy_addr = addr;
1872}
1873
1874
1875u_short
1876GetProxyPort(struct alias_link *link)
1877{
1878 return link->proxy_port;
1879}
1880
1881
1882void
1883SetProxyPort(struct alias_link *link, u_short port)
1884{
1885 link->proxy_port = port;
1886}
1887
1888
1889int
1890GetAckModified(struct alias_link *link)
1891{
1892/* See if ACK numbers have been modified */
1893 return link->data.tcp->state.ack_modified;
1894}
1895
1896
1897int
1898GetDeltaAckIn(struct ip *pip, struct alias_link *link)
1899{
1900/*
1901Find out how much the ACK number has been altered for an incoming
1902TCP packet. To do this, a circular list of ACK numbers where the TCP
1903packet size was altered is searched.
1904*/
1905
1906 int i;
1907 struct tcphdr *tc;
1908 int delta, ack_diff_min;
1909 u_long ack;
1910
1911 tc = (struct tcphdr *)((char *)pip + (pip->ip_hl << 2));
1912 ack = tc->th_ack;
1913
1914 delta = 0;
1915 ack_diff_min = -1;
1916 for (i = 0; i < N_LINK_TCP_DATA; i++) {
1917 struct ack_data_record x;
1918
1919 x = link->data.tcp->ack[i];
1920 if (x.active == 1) {
1921 int ack_diff;
1922
1923 ack_diff = SeqDiff(x.ack_new, ack);
1924 if (ack_diff >= 0) {
1925 if (ack_diff_min >= 0) {
1926 if (ack_diff < ack_diff_min) {
1927 delta = x.delta;
1928 ack_diff_min = ack_diff;
1929 }
1930 } else {
1931 delta = x.delta;
1932 ack_diff_min = ack_diff;
1933 }
1934 }
1935 }
1936 }
1937 return (delta);
1938}
1939
1940
1941int
1942GetDeltaSeqOut(struct ip *pip, struct alias_link *link)
1943{
1944/*
1945Find out how much the sequence number has been altered for an outgoing
1946TCP packet. To do this, a circular list of ACK numbers where the TCP
1947packet size was altered is searched.
1948*/
1949
1950 int i;
1951 struct tcphdr *tc;
1952 int delta, seq_diff_min;
1953 u_long seq;
1954
1955 tc = (struct tcphdr *)((char *)pip + (pip->ip_hl << 2));
1956 seq = tc->th_seq;
1957
1958 delta = 0;
1959 seq_diff_min = -1;
1960 for (i = 0; i < N_LINK_TCP_DATA; i++) {
1961 struct ack_data_record x;
1962
1963 x = link->data.tcp->ack[i];
1964 if (x.active == 1) {
1965 int seq_diff;
1966
1967 seq_diff = SeqDiff(x.ack_old, seq);
1968 if (seq_diff >= 0) {
1969 if (seq_diff_min >= 0) {
1970 if (seq_diff < seq_diff_min) {
1971 delta = x.delta;
1972 seq_diff_min = seq_diff;
1973 }
1974 } else {
1975 delta = x.delta;
1976 seq_diff_min = seq_diff;
1977 }
1978 }
1979 }
1980 }
1981 return (delta);
1982}
1983
1984
1985void
1986AddSeq(struct ip *pip, struct alias_link *link, int delta)
1987{
1988/*
1989When a TCP packet has been altered in length, save this
1990information in a circular list. If enough packets have
1991been altered, then this list will begin to overwrite itself.
1992*/
1993
1994 struct tcphdr *tc;
1995 struct ack_data_record x;
1996 int hlen, tlen, dlen;
1997 int i;
1998
1999 tc = (struct tcphdr *)((char *)pip + (pip->ip_hl << 2));
2000
2001 hlen = (pip->ip_hl + tc->th_off) << 2;
2002 tlen = ntohs(pip->ip_len);
2003 dlen = tlen - hlen;
2004
2005 x.ack_old = htonl(ntohl(tc->th_seq) + dlen);
2006 x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta);
2007 x.delta = delta;
2008 x.active = 1;
2009
2010 i = link->data.tcp->state.index;
2011 link->data.tcp->ack[i] = x;
2012
2013 i++;
2014 if (i == N_LINK_TCP_DATA)
2015 link->data.tcp->state.index = 0;
2016 else
2017 link->data.tcp->state.index = i;
2018}
2019
2020void
2021SetExpire(struct alias_link *link, int expire)
2022{
2023 if (expire == 0) {
2024 link->flags &= ~LINK_PERMANENT;
2025 DeleteLink(link);
2026 } else if (expire == -1) {
2027 link->flags |= LINK_PERMANENT;
2028 } else if (expire > 0) {
2029 link->expire_time = expire;
2030 } else {
2031#ifdef DEBUG
2032 fprintf(stderr, "PacketAlias/SetExpire(): ");
2033 fprintf(stderr, "error in expire parameter\n");
2034#endif
2035 }
2036}
2037
2038void
2039ClearCheckNewLink(struct libalias *la)
2040{
2041 la->newDefaultLink = 0;
2042}
2043
2044void
2045SetProtocolFlags(struct alias_link *link, int pflags)
2046{
2047
2048 link->pflags = pflags;;
2049}
2050
2051int
2052GetProtocolFlags(struct alias_link *link)
2053{
2054
2055 return (link->pflags);
2056}
2057
2058void
2059SetDestCallId(struct alias_link *link, u_int16_t cid)
2060{
2061 struct libalias *la = link->la;
2062
2063 la->deleteAllLinks = 1;
2064 link = ReLink(link, link->src_addr, link->dst_addr, link->alias_addr,
2065 link->src_port, cid, link->alias_port, link->link_type);
2066 la->deleteAllLinks = 0;
2067}
2068
2069
2070/* Miscellaneous Functions
2071
2072 HouseKeeping()
2073 InitPacketAliasLog()
2074 UninitPacketAliasLog()

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

2081 every 60 seconds.
2082
2083 (prototype in alias_local.h)
2084*/
2085
2086void
2087HouseKeeping(struct libalias *la)
2088{
2089 int i, n, n100;
2090 struct timeval tv;
2091 struct timezone tz;
2092
2093 /*
2094 * Save system time (seconds) in global variable timeStamp for use
2095 * by other functions. This is done so as not to unnecessarily
2096 * waste timeline by making system calls.
2097 */
2098 gettimeofday(&tv, &tz);
2099 la->timeStamp = tv.tv_sec;
2100
2101 /* Compute number of spokes (output table link chains) to cover */
2102 n100 = LINK_TABLE_OUT_SIZE * 100 + la->houseKeepingResidual;
2103 n100 *= la->timeStamp - la->lastCleanupTime;
2104 n100 /= ALIAS_CLEANUP_INTERVAL_SECS;
2105
2106 n = n100 / 100;
2107
2108 /* Handle different cases */
2109 if (n > ALIAS_CLEANUP_MAX_SPOKES) {
2110 n = ALIAS_CLEANUP_MAX_SPOKES;
2111 la->lastCleanupTime = la->timeStamp;
2112 la->houseKeepingResidual = 0;
2113
2114 for (i = 0; i < n; i++)
2115 IncrementalCleanup(la);
2116 } else if (n > 0) {
2117 la->lastCleanupTime = la->timeStamp;
2118 la->houseKeepingResidual = n100 - 100 * n;
2119
2120 for (i = 0; i < n; i++)
2121 IncrementalCleanup(la);
2122 } else if (n < 0) {
2123#ifdef DEBUG
2124 fprintf(stderr, "PacketAlias/HouseKeeping(): ");
2125 fprintf(stderr, "something unexpected in time values\n");
2126#endif
2127 la->lastCleanupTime = la->timeStamp;
2128 la->houseKeepingResidual = 0;
2129 }
2130}
2131
2132
2133/* Init the log file and enable logging */
2134static void
2135InitPacketAliasLog(struct libalias *la)
2136{
2137 if ((~la->packetAliasMode & PKT_ALIAS_LOG)
2138 && (la->monitorFile = fopen("/var/log/alias.log", "w"))) {
2139 la->packetAliasMode |= PKT_ALIAS_LOG;
2140 fprintf(la->monitorFile,
2141 "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
2142 }
2143}
2144
2145
2146/* Close the log-file and disable logging. */
2147static void
2148UninitPacketAliasLog(struct libalias *la)
2149{
2150 if (la->monitorFile) {
2151 fclose(la->monitorFile);
2152 la->monitorFile = NULL;
2153 }
2154 la->packetAliasMode &= ~PKT_ALIAS_LOG;
2155}
2156
2157
2158
2159
2160
2161
2162/* Outside world interfaces

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

2175 PacketAliasSetMode()
2176
2177(prototypes in alias.h)
2178*/
2179
2180/* Redirection from a specific public addr:port to a
2181 private addr:port */
2182struct alias_link *
2183LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port,
2184 struct in_addr dst_addr, u_short dst_port,
2185 struct in_addr alias_addr, u_short alias_port,
2186 u_char proto)
2187{
2188 int link_type;
2189 struct alias_link *link;
2190
2191 switch (proto) {
2192 case IPPROTO_UDP:
2193 link_type = LINK_UDP;
2194 break;
2195 case IPPROTO_TCP:
2196 link_type = LINK_TCP;
2197 break;
2198 default:
2199#ifdef DEBUG
2200 fprintf(stderr, "PacketAliasRedirectPort(): ");
2201 fprintf(stderr, "only TCP and UDP protocols allowed\n");
2202#endif
2203 return NULL;
2204 }
2205
2206 link = AddLink(la, src_addr, dst_addr, alias_addr,
2207 src_port, dst_port, alias_port,
2208 link_type);
2209
2210 if (link != NULL) {
2211 link->flags |= LINK_PERMANENT;
2212 }
2213#ifdef DEBUG
2214 else {
2215 fprintf(stderr, "PacketAliasRedirectPort(): "
2216 "call to AddLink() failed\n");
2217 }
2218#endif
2219
2220 return link;
2221}
2222
2223/* Add server to the pool of servers */
2224int
2225LibAliasAddServer(struct libalias *la, struct alias_link *link, struct in_addr addr, u_short port)
2226{
2227 struct server *server;
2228
2229 server = malloc(sizeof(struct server));
2230
2231 if (server != NULL) {
2232 struct server *head;
2233
2234 server->addr = addr;
2235 server->port = port;
2236
2237 head = link->server;
2238 if (head == NULL)
2239 server->next = server;
2240 else {
2241 struct server *s;
2242
2243 for (s = head; s->next != head; s = s->next);
2244 s->next = server;
2245 server->next = head;
2246 }
2247 link->server = server;
2248 return (0);
2249 } else
2250 return (-1);
2251}
2252
2253/* Redirect packets of a given IP protocol from a specific
2254 public address to a private address */
2255struct alias_link *
2256LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr,
2257 struct in_addr dst_addr,
2258 struct in_addr alias_addr,
2259 u_char proto)
2260{
2261 struct alias_link *link;
2262
2263 link = AddLink(la, src_addr, dst_addr, alias_addr,
2264 NO_SRC_PORT, NO_DEST_PORT, 0,
2265 proto);
2266
2267 if (link != NULL) {
2268 link->flags |= LINK_PERMANENT;
2269 }
2270#ifdef DEBUG
2271 else {
2272 fprintf(stderr, "PacketAliasRedirectProto(): "
2273 "call to AddLink() failed\n");
2274 }
2275#endif
2276
2277 return link;
2278}
2279
2280/* Static address translation */
2281struct alias_link *
2282LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr,
2283 struct in_addr alias_addr)
2284{
2285 struct alias_link *link;
2286
2287 link = AddLink(la, src_addr, la->nullAddress, alias_addr,
2288 0, 0, 0,
2289 LINK_ADDR);
2290
2291 if (link != NULL) {
2292 link->flags |= LINK_PERMANENT;
2293 }
2294#ifdef DEBUG
2295 else {
2296 fprintf(stderr, "PacketAliasRedirectAddr(): "
2297 "call to AddLink() failed\n");
2298 }
2299#endif
2300
2301 return link;
2302}
2303
2304
2305/* Mark the aliasing link dynamic */
2306int
2307LibAliasRedirectDynamic(struct libalias *la, struct alias_link *link)
2308{
2309
2310 if (link->flags & LINK_PARTIALLY_SPECIFIED)
2311 return (-1);
2312 else {
2313 link->flags &= ~LINK_PERMANENT;
2314 return (0);
2315 }
2316}
2317
2318
2319void
2320LibAliasRedirectDelete(struct libalias *la, struct alias_link *link)
2321{
2322/* This is a dangerous function to put in the API,
2323 because an invalid pointer can crash the program. */
2324
2325 la->deleteAllLinks = 1;
2326 DeleteLink(link);
2327 la->deleteAllLinks = 0;
2328}
2329
2330
2331void
2332LibAliasSetAddress(struct libalias *la, struct in_addr addr)
2333{
2334 if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2335 && la->aliasAddress.s_addr != addr.s_addr)
2336 CleanupAliasData(la);
2337
2338 la->aliasAddress = addr;
2339}
2340
2341
2342void
2343LibAliasSetTarget(struct libalias *la, struct in_addr target_addr)
2344{
2345 la->targetAddress = target_addr;
2346}
2347
2348static void
2349finishoff(void)
2350{
2351
2352 while (!LIST_EMPTY(&instancehead))
2353 LibAliasUninit(LIST_FIRST(&instancehead));
2354}
2355
2356struct libalias *
2357LibAliasInit(struct libalias *la)
2358{
2359 int i;
2360 struct timeval tv;
2361 struct timezone tz;
2362
2363 if (la == NULL) {
2364 la = calloc(sizeof *la, 1);
2365 if (la == NULL)
2366 return (la);
2367 if (LIST_EMPTY(&instancehead))
2368 atexit(finishoff);
2369 LIST_INSERT_HEAD(&instancehead, la, instancelist);
2370
2371 gettimeofday(&tv, &tz);
2372 la->timeStamp = tv.tv_sec;
2373 la->lastCleanupTime = tv.tv_sec;
2374 la->houseKeepingResidual = 0;
2375
2376 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++)
2377 LIST_INIT(&la->linkTableOut[i]);
2378 for (i = 0; i < LINK_TABLE_IN_SIZE; i++)
2379 LIST_INIT(&la->linkTableIn[i]);
2380
2381 } else {
2382 la->deleteAllLinks = 1;
2383 CleanupAliasData(la);
2384 la->deleteAllLinks = 0;
2385 }
2386
2387 la->aliasAddress.s_addr = INADDR_ANY;
2388 la->targetAddress.s_addr = INADDR_ANY;
2389
2390 la->icmpLinkCount = 0;
2391 la->udpLinkCount = 0;
2392 la->tcpLinkCount = 0;
2393 la->pptpLinkCount = 0;
2394 la->protoLinkCount = 0;
2395 la->fragmentIdLinkCount = 0;
2396 la->fragmentPtrLinkCount = 0;
2397 la->sockCount = 0;
2398
2399 la->cleanupIndex = 0;
2400
2401 la->packetAliasMode = PKT_ALIAS_SAME_PORTS
2402 | PKT_ALIAS_USE_SOCKETS
2403 | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2404#ifndef NO_FW_PUNCH
2405 la->fireWallFD = -1;
2406#endif
2407 return (la);
2408}
2409
2410void
2411LibAliasUninit(struct libalias *la)
2412{
2413 la->deleteAllLinks = 1;
2414 CleanupAliasData(la);
2415 la->deleteAllLinks = 0;
2416 UninitPacketAliasLog(la);
2417#ifndef NO_FW_PUNCH
2418 UninitPunchFW(la);
2419#endif
2420 LIST_REMOVE(la, instancelist);
2421 free(la);
2422}
2423
2424/* Change mode for some operations */
2425unsigned int
2426LibAliasSetMode(
2427 struct libalias *la,
2428 unsigned int flags, /* Which state to bring flags to */
2429 unsigned int mask /* Mask of which flags to affect (use 0 to
2430 * do a probe for flag values) */
2431)
2432{
2433/* Enable logging? */
2434 if (flags & mask & PKT_ALIAS_LOG) {
2435 InitPacketAliasLog(la); /* Do the enable */
2436 } else
2437/* _Disable_ logging? */
2438 if (~flags & mask & PKT_ALIAS_LOG) {
2439 UninitPacketAliasLog(la);
2440 }
2441#ifndef NO_FW_PUNCH
2442/* Start punching holes in the firewall? */
2443 if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2444 InitPunchFW(la);
2445 } else
2446/* Stop punching holes in the firewall? */
2447 if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2448 UninitPunchFW(la);
2449 }
2450#endif
2451
2452/* Other flags can be set/cleared without special action */
2453 la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask);
2454 return la->packetAliasMode;
2455}
2456
2457
2458int
2459LibAliasCheckNewLink(struct libalias *la)
2460{
2461 return la->newDefaultLink;
2462}
2463
2464
2465#ifndef NO_FW_PUNCH
2466
2467/*****************
2468 Code to support firewall punching. This shouldn't really be in this
2469 file, but making variables global is evil too.
2470 ****************/
2471
2472#ifndef IPFW2
2473#define IPFW2 1 /* use new ipfw code */
2474#endif
2475
2476/* Firewall include files */
2477#include <net/if.h>
2478#include <netinet/ip_fw.h>
2479#include <string.h>
2480#include <err.h>
2481
2482#if IPFW2 /* support for new firewall code */
2483/*
2484 * helper function, updates the pointer to cmd with the length
2485 * of the current command, and also cleans up the first word of
2486 * the new command in case it has been clobbered before.
2487 */
2488static ipfw_insn *
2489next_cmd(ipfw_insn * cmd)
2490{
2491 cmd += F_LEN(cmd);
2492 bzero(cmd, sizeof(*cmd));
2493 return cmd;
2494}
2495
2496/*
2497 * A function to fill simple commands of size 1.
2498 * Existing flags are preserved.
2499 */
2500static ipfw_insn *
2501fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size,
2502 int flags, u_int16_t arg)
2503{
2504 cmd->opcode = opcode;
2505 cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK);
2506 cmd->arg1 = arg;
2507 return next_cmd(cmd);
2508}
2509
2510static ipfw_insn *
2511fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr)
2512{
2513 ipfw_insn_ip *cmd = (ipfw_insn_ip *) cmd1;
2514
2515 cmd->addr.s_addr = addr;
2516 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0);
2517}
2518
2519static ipfw_insn *
2520fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port)
2521{
2522 ipfw_insn_u16 *cmd = (ipfw_insn_u16 *) cmd1;
2523
2524 cmd->ports[0] = cmd->ports[1] = port;
2525 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0);
2526}
2527
2528static int
2529fill_rule(void *buf, int bufsize, int rulenum,
2530 enum ipfw_opcodes action, int proto,
2531 struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp)
2532{
2533 struct ip_fw *rule = (struct ip_fw *)buf;
2534 ipfw_insn *cmd = (ipfw_insn *) rule->cmd;
2535
2536 bzero(buf, bufsize);
2537 rule->rulenum = rulenum;
2538
2539 cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto);
2540 cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr);
2541 cmd = fill_one_port(cmd, O_IP_SRCPORT, sp);
2542 cmd = fill_ip(cmd, O_IP_DST, da.s_addr);
2543 cmd = fill_one_port(cmd, O_IP_DSTPORT, dp);
2544
2545 rule->act_ofs = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2546 cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0);
2547
2548 rule->cmd_len = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2549
2550 return ((char *)cmd - (char *)buf);
2551}
2552
2553#endif /* IPFW2 */
2554
2555static void ClearAllFWHoles(struct libalias *la);
2556
2557
2558#define fw_setfield(la, field, num) \
2559do { \
2560 (field)[(num) - la->fireWallBaseNum] = 1; \
2561} /*lint -save -e717 */ while(0)/* lint -restore */
2562
2563#define fw_clrfield(la, field, num) \
2564do { \
2565 (field)[(num) - la->fireWallBaseNum] = 0; \
2566} /*lint -save -e717 */ while(0)/* lint -restore */
2567
2568#define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum])
2569
2570static void
2571InitPunchFW(struct libalias *la)
2572{
2573
2574 la->fireWallField = malloc(la->fireWallNumNums);
2575 if (la->fireWallField) {
2576 memset(la->fireWallField, 0, la->fireWallNumNums);
2577 if (la->fireWallFD < 0) {
2578 la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2579 }
2580 ClearAllFWHoles(la);
2581 la->fireWallActiveNum = la->fireWallBaseNum;
2582 }
2583}
2584
2585static void
2586UninitPunchFW(struct libalias *la)
2587{
2588 ClearAllFWHoles(la);
2589 if (la->fireWallFD >= 0)
2590 close(la->fireWallFD);
2591 la->fireWallFD = -1;
2592 if (la->fireWallField)
2593 free(la->fireWallField);
2594 la->fireWallField = NULL;
2595 la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2596}
2597
2598/* Make a certain link go through the firewall */
2599void
2600PunchFWHole(struct alias_link *link)
2601{
2602 struct libalias *la;
2603 int r; /* Result code */
2604 struct ip_fw rule; /* On-the-fly built rule */
2605 int fwhole; /* Where to punch hole */
2606
2607 la = link->la;
2608
2609/* Don't do anything unless we are asked to */
2610 if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2611 la->fireWallFD < 0 ||
2612 link->link_type != LINK_TCP)
2613 return;
2614
2615 memset(&rule, 0, sizeof rule);
2616
2617/** Build rule **/
2618
2619 /* Find empty slot */
2620 for (fwhole = la->fireWallActiveNum;
2621 fwhole < la->fireWallBaseNum + la->fireWallNumNums &&
2622 fw_tstfield(la, la->fireWallField, fwhole);
2623 fwhole++);
2624 if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) {
2625 for (fwhole = la->fireWallBaseNum;
2626 fwhole < la->fireWallActiveNum &&
2627 fw_tstfield(la, la->fireWallField, fwhole);
2628 fwhole++);
2629 if (fwhole == la->fireWallActiveNum) {
2630 /* No rule point empty - we can't punch more holes. */
2631 la->fireWallActiveNum = la->fireWallBaseNum;
2632#ifdef DEBUG
2633 fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2634#endif
2635 return;
2636 }
2637 }
2638 /* Start next search at next position */
2639 la->fireWallActiveNum = fwhole + 1;
2640
2641 /*
2642 * generate two rules of the form
2643 *
2644 * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole
2645 * accept tcp from DAddr DPort to OAddr OPort
2646 */
2647#if IPFW2
2648 if (GetOriginalPort(link) != 0 && GetDestPort(link) != 0) {
2649 u_int32_t rulebuf[255];
2650 int i;
2651
2652 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2653 O_ACCEPT, IPPROTO_TCP,
2654 GetOriginalAddress(link), ntohs(GetOriginalPort(link)),
2655 GetDestAddress(link), ntohs(GetDestPort(link)));
2656 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2657 if (r)
2658 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2659
2660 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2661 O_ACCEPT, IPPROTO_TCP,
2662 GetDestAddress(link), ntohs(GetDestPort(link)),
2663 GetOriginalAddress(link), ntohs(GetOriginalPort(link)));
2664 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2665 if (r)
2666 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2667 }
2668#else /* !IPFW2, old code to generate ipfw rule */
2669
2670 /* Build generic part of the two rules */
2671 rule.fw_number = fwhole;
2672 IP_FW_SETNSRCP(&rule, 1); /* Number of source ports. */
2673 IP_FW_SETNDSTP(&rule, 1); /* Number of destination ports. */
2674 rule.fw_flg = IP_FW_F_ACCEPT | IP_FW_F_IN | IP_FW_F_OUT;
2675 rule.fw_prot = IPPROTO_TCP;
2676 rule.fw_smsk.s_addr = INADDR_BROADCAST;
2677 rule.fw_dmsk.s_addr = INADDR_BROADCAST;
2678
2679 /* Build and apply specific part of the rules */
2680 rule.fw_src = GetOriginalAddress(link);
2681 rule.fw_dst = GetDestAddress(link);
2682 rule.fw_uar.fw_pts[0] = ntohs(GetOriginalPort(link));
2683 rule.fw_uar.fw_pts[1] = ntohs(GetDestPort(link));
2684
2685 /*
2686 * Skip non-bound links - XXX should not be strictly necessary, but
2687 * seems to leave hole if not done. Leak of non-bound links? (Code
2688 * should be left even if the problem is fixed - it is a clear
2689 * optimization)
2690 */
2691 if (rule.fw_uar.fw_pts[0] != 0 && rule.fw_uar.fw_pts[1] != 0) {
2692 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
2693#ifdef DEBUG
2694 if (r)
2695 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2696#endif
2697 rule.fw_src = GetDestAddress(link);
2698 rule.fw_dst = GetOriginalAddress(link);
2699 rule.fw_uar.fw_pts[0] = ntohs(GetDestPort(link));
2700 rule.fw_uar.fw_pts[1] = ntohs(GetOriginalPort(link));
2701 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
2702#ifdef DEBUG
2703 if (r)
2704 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2705#endif
2706 }
2707#endif /* !IPFW2 */
2708/* Indicate hole applied */
2709 link->data.tcp->fwhole = fwhole;
2710 fw_setfield(la, la->fireWallField, fwhole);
2711}
2712
2713/* Remove a hole in a firewall associated with a particular alias
2714 link. Calling this too often is harmless. */
2715static void
2716ClearFWHole(struct alias_link *link)
2717{
2718
2719 struct libalias *la;
2720
2721 la = link->la;
2722 if (link->link_type == LINK_TCP) {
2723 int fwhole = link->data.tcp->fwhole; /* Where is the firewall
2724 * hole? */
2725 struct ip_fw rule;
2726
2727 if (fwhole < 0)
2728 return;
2729
2730 memset(&rule, 0, sizeof rule); /* useless for ipfw2 */
2731#if IPFW2
2732 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL,
2733 &fwhole, sizeof fwhole));
2734#else /* !IPFW2 */
2735 rule.fw_number = fwhole;
2736 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL,
2737 &rule, sizeof rule));
2738#endif /* !IPFW2 */
2739 fw_clrfield(la, la->fireWallField, fwhole);
2740 link->data.tcp->fwhole = -1;
2741 }
2742}
2743
2744/* Clear out the entire range dedicated to firewall holes. */
2745static void
2746ClearAllFWHoles(struct libalias *la)
2747{
2748 struct ip_fw rule; /* On-the-fly built rule */
2749 int i;
2750
2751 if (la->fireWallFD < 0)
2752 return;
2753
2754 memset(&rule, 0, sizeof rule);
2755 for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) {
2756#if IPFW2
2757 int r = i;
2758
2759 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r));
2760#else /* !IPFW2 */
2761 rule.fw_number = i;
2762 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule));
2763#endif /* !IPFW2 */
2764 }
2765 /* XXX: third arg correct here ? /phk */
2766 memset(la->fireWallField, 0, la->fireWallNumNums);
2767}
2768
2769#endif
2770
2771void
2772LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num)
2773{
2774#ifndef NO_FW_PUNCH
2775 la->fireWallBaseNum = base;
2776 la->fireWallNumNums = num;
2777#endif
2778}
2779
2780void
2781LibAliasSetSkinnyPort(struct libalias *la, unsigned int port)
2782{
2783 la->skinnyPort = port;
2784}