Index: sys/netinet/libalias/alias_db.c =================================================================== --- sys/netinet/libalias/alias_db.c +++ sys/netinet/libalias/alias_db.c @@ -220,9 +220,8 @@ #define NO_DEST_PORT 1 #define NO_SRC_PORT 1 -/* Dummy address used for FindLinkIn/Out() and AddLink(). - The value of this variable is never used. */ -static struct in_addr const NO_ADDR; +/* Matches any/unknown address in FindLinkIn/Out() and AddLink(). */ +static struct in_addr const ANY_ADDR = { INADDR_ANY }; /* Data Structures @@ -319,14 +318,23 @@ #define LINK_UNFIREWALLED 0x08 int timestamp; /* Time link was last accessed */ - int expire_time; /* Expire time for link */ #ifndef NO_USE_SOCKETS int sockfd; /* socket descriptor */ #endif /* Linked list of pointers for input and output lookup tables */ - LIST_ENTRY (alias_link) list_out; - LIST_ENTRY (alias_link) list_in; - TAILQ_ENTRY (alias_link) list_expire; + union { + struct { + LIST_ENTRY(alias_link) in; + LIST_ENTRY(alias_link) out; + } all; + struct { + LIST_ENTRY(alias_link) list; + } pptp; + }; + struct { + TAILQ_ENTRY(alias_link) list; + int timeout; /* Expire time for link */ + } expire; /* Auxiliary data */ union { char *frag_ptr; @@ -379,12 +387,10 @@ */ /* Local prototypes */ -static u_int StartPointIn(struct in_addr, u_short, int); - -static u_int -StartPointOut(struct in_addr, struct in_addr, - u_short, u_short, int); - +static struct group_in * +StartPointIn(struct libalias *, struct in_addr, u_short, int, int); +static u_int +StartPointOut(struct in_addr, struct in_addr, u_short, u_short, int); static int SeqDiff(u_long, u_long); #ifndef NO_FW_PUNCH @@ -402,19 +408,46 @@ void SctpShowAliasStats(struct libalias *la); -static u_int -StartPointIn(struct in_addr alias_addr, - u_short alias_port, - int link_type) +#define INGUARD \ + if (grp->alias_port != alias_port || \ + grp->link_type != link_type || \ + grp->alias_addr.s_addr != alias_addr.s_addr) \ + continue; + +static struct group_in * +StartPointIn(struct libalias *la, + struct in_addr alias_addr, u_short alias_port, int link_type, + int create) { u_int n; + struct group_in *grp, *tmp; n = alias_addr.s_addr; - if (link_type != LINK_PPTP) - n += alias_port; + n += alias_port; n += link_type; - return (n % LINK_TABLE_IN_SIZE); -} + n %= LINK_TABLE_IN_SIZE; + + LIST_FOREACH_SAFE(grp, &la->groupTableIn[n], group_in, tmp) { + /* Auto cleanup */ + if (LIST_EMPTY(&grp->full) && LIST_EMPTY(&grp->partial)) { + LIST_REMOVE(grp, group_in); + free(grp); + } else { + INGUARD; + return (grp); + } + } + if (!create || (grp = malloc(sizeof(*grp))) == NULL) + return (grp); + grp->alias_addr = alias_addr; + grp->alias_port = alias_port; + grp->link_type = link_type; + LIST_INIT(&grp->full); + LIST_INIT(&grp->partial); + LIST_INSERT_HEAD(&la->groupTableIn[n], grp, group_in); + return (grp); +} +#undef INGUARD static u_int StartPointOut(struct in_addr src_addr, struct in_addr dst_addr, @@ -424,10 +457,8 @@ n = src_addr.s_addr; n += dst_addr.s_addr; - if (link_type != LINK_PPTP) { - n += src_port; - n += dst_port; - } + n += src_port; + n += dst_port; n += link_type; return (n % LINK_TABLE_OUT_SIZE); @@ -529,6 +560,8 @@ static void CleanupAliasData(struct libalias *); static void CleanupLink(struct libalias *, struct alias_link **); static void DeleteLink(struct alias_link **); +static struct alias_link * +UseLink(struct libalias *, struct alias_link *); static struct alias_link * ReLink(struct alias_link *, @@ -541,12 +574,20 @@ static struct alias_link * FindLinkIn(struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int); -#define ALIAS_PORT_BASE 0x08000 -#define ALIAS_PORT_MASK 0x07fff -#define ALIAS_PORT_MASK_EVEN 0x07ffe +static u_short _RandomPort(struct libalias *la); + #define GET_NEW_PORT_MAX_ATTEMPTS 20 -#define FIND_EVEN_ALIAS_BASE 1 +/* get random port in network byte order */ +static u_short +_RandomPort(struct libalias *la) { + u_short port; + + port = la->aliasPortLower + + (arc4random() % la->aliasPortLength); + + return ntohs(port); +} /* GetNewPort() allocates port numbers. Note that if a port number is already in use, that does not mean that it cannot be used by @@ -558,8 +599,7 @@ { int i; int max_trials; - u_short port_sys; - u_short port_net; + u_short port; LIBALIAS_LOCK_ASSERT(la); /* @@ -567,41 +607,18 @@ * this parameter is zero or positive, it precisely specifies * the port number. GetNewPort() will return this number * without check that it is in use. - + * + * The aliasing port is automatically selected by one of + * two methods below: + * * When this parameter is GET_ALIAS_PORT, it indicates to get * a randomly selected port number. */ - if (alias_port_param == GET_ALIAS_PORT) { - /* - * The aliasing port is automatically selected by one of - * two methods below: - */ - max_trials = GET_NEW_PORT_MAX_ATTEMPTS; - - if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) { - /* - * When the PKT_ALIAS_SAME_PORTS option is chosen, - * the first try will be the actual source port. If - * this is already in use, the remainder of the - * trials will be random. - */ - port_net = lnk->src_port; - port_sys = ntohs(port_net); - } else if (la->aliasPortLower) { - /* First trial is a random port in the aliasing range. */ - port_sys = la->aliasPortLower + - (arc4random() % la->aliasPortLength); - port_net = htons(port_sys); - } else { - /* First trial and all subsequent are random. */ - port_sys = arc4random() & ALIAS_PORT_MASK; - port_sys += ALIAS_PORT_BASE; - port_net = htons(port_sys); - } - } else if (alias_port_param >= 0 && alias_port_param < 0x10000) { + if (alias_port_param >= 0 && alias_port_param < 0x10000) { lnk->alias_port = (u_short) alias_port_param; return (0); - } else { + } + if (alias_port_param != GET_ALIAS_PORT) { #ifdef LIBALIAS_DEBUG fprintf(stderr, "PacketAlias/GetNewPort(): "); fprintf(stderr, "input parameter error\n"); @@ -609,58 +626,57 @@ return (-1); } + max_trials = GET_NEW_PORT_MAX_ATTEMPTS; + + /* + * When the PKT_ALIAS_SAME_PORTS option is chosen, + * the first try will be the actual source port. If + * this is already in use, the remainder of the + * trials will be random. + */ + port = (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) + ? lnk->src_port + : _RandomPort(la); + /* Port number search */ - for (i = 0; i < max_trials; i++) { - int go_ahead; + for (i = 0; i < max_trials; i++, port = _RandomPort(la)) { + struct group_in *grp; struct alias_link *search_result; - search_result = FindLinkIn(la, lnk->dst_addr, lnk->alias_addr, - lnk->dst_port, port_net, - lnk->link_type, 0); + grp = StartPointIn(la, lnk->alias_addr, port, lnk->link_type, 0); + if (grp == NULL) + break; + LIST_FOREACH(search_result, &grp->full, all.in) { + if (lnk->dst_addr.s_addr == search_result->dst_addr.s_addr && + lnk->dst_port == search_result->dst_port) + break; /* found match */ + } if (search_result == NULL) - go_ahead = 1; - else if (!(lnk->flags & LINK_PARTIALLY_SPECIFIED) - && (search_result->flags & LINK_PARTIALLY_SPECIFIED)) - go_ahead = 1; - else - go_ahead = 0; + break; + } - if (go_ahead) { -#ifndef NO_USE_SOCKETS - if ((la->packetAliasMode & PKT_ALIAS_USE_SOCKETS) - && (lnk->flags & LINK_PARTIALLY_SPECIFIED) - && ((lnk->link_type == LINK_TCP) || - (lnk->link_type == LINK_UDP))) { - if (GetSocket(la, port_net, &lnk->sockfd, lnk->link_type)) { - lnk->alias_port = port_net; - return (0); - } - } else { + if (i >= max_trials) { +#ifdef LIBALIAS_DEBUG + fprintf(stderr, "PacketAlias/GetNewPort(): "); + fprintf(stderr, "could not find free port\n"); #endif - lnk->alias_port = port_net; - return (0); + return (-1); + } + #ifndef NO_USE_SOCKETS - } -#endif - } - if (la->aliasPortLower) { - port_sys = la->aliasPortLower + - (arc4random() % la->aliasPortLength); - port_net = htons(port_sys); - } else { - port_sys = arc4random() & ALIAS_PORT_MASK; - port_sys += ALIAS_PORT_BASE; - port_net = htons(port_sys); + if ((la->packetAliasMode & PKT_ALIAS_USE_SOCKETS) && + (lnk->flags & LINK_PARTIALLY_SPECIFIED) && + ((lnk->link_type == LINK_TCP) || + (lnk->link_type == LINK_UDP))) { + if (!GetSocket(la, port, &lnk->sockfd, lnk->link_type)) { + return (-1); } } - -#ifdef LIBALIAS_DEBUG - fprintf(stderr, "PacketAlias/GetNewPort(): "); - fprintf(stderr, "could not find free port\n"); #endif + lnk->alias_port = port; - return (-1); + return (0); } #ifndef NO_USE_SOCKETS @@ -727,7 +743,7 @@ { int i, j; int max_trials; - u_short port_sys; + u_short port; int link_type; LIBALIAS_LOCK_ASSERT(la); @@ -759,39 +775,31 @@ * try will be the actual source port. If this is already * in use, the remainder of the trials will be random. */ - port_sys = ntohs(src_port); + port = src_port; } else { - /* First trial and all subsequent are random. */ - if (align == FIND_EVEN_ALIAS_BASE) - port_sys = arc4random() & ALIAS_PORT_MASK_EVEN; - else - port_sys = arc4random() & ALIAS_PORT_MASK; - - port_sys += ALIAS_PORT_BASE; + port = _RandomPort(la); } /* Port number search */ - for (i = 0; i < max_trials; i++) { + for (i = 0; i < max_trials; i++, port = _RandomPort(la)) { struct alias_link *search_result; - for (j = 0; j < port_count; j++) + if (align) + port &= htons(0xfffe); + + for (j = 0; j < port_count; j++) { + u_short port_j = ntohs(port) + j; + if ((search_result = FindLinkIn(la, dst_addr, - alias_addr, dst_port, htons(port_sys + j), + alias_addr, dst_port, htons(port_j), link_type, 0)) != NULL) break; + } /* Found a good range, return base */ if (j == port_count) - return (htons(port_sys)); - - /* Find a new base to try */ - if (align == FIND_EVEN_ALIAS_BASE) - port_sys = arc4random() & ALIAS_PORT_MASK_EVEN; - else - port_sys = arc4random() & ALIAS_PORT_MASK; - - port_sys += ALIAS_PORT_BASE; + return (port); } #ifdef LIBALIAS_DEBUG @@ -806,12 +814,23 @@ CleanupAliasData(struct libalias *la) { struct alias_link *lnk, *lnk_tmp; + u_int i; LIBALIAS_LOCK_ASSERT(la); /* permanent entries may stay */ - TAILQ_FOREACH_SAFE(lnk, &la->checkExpire, list_expire, lnk_tmp) + TAILQ_FOREACH_SAFE(lnk, &la->checkExpire, expire.list, lnk_tmp) DeleteLink(&lnk); + + for (i = 0; i < LINK_TABLE_IN_SIZE; i++) { + struct group_in *grp, *grp_tmp; + + LIST_FOREACH_SAFE(grp, &la->groupTableIn[i], group_in, grp_tmp) + if (LIST_EMPTY(&grp->full) && LIST_EMPTY(&grp->partial)) { + LIST_REMOVE(grp, group_in); + free(grp); + } + } } static void @@ -822,15 +841,24 @@ if (lnk == NULL || *lnk == NULL) return; - if (LibAliasTime - (*lnk)->timestamp > (*lnk)->expire_time) { + if (LibAliasTime - (*lnk)->timestamp > (*lnk)->expire.timeout) { DeleteLink(lnk); if ((*lnk) == NULL) return; } /* move to end, swap may fail on a single entry list */ - TAILQ_REMOVE(&la->checkExpire, (*lnk), list_expire); - TAILQ_INSERT_TAIL(&la->checkExpire, (*lnk), list_expire); + TAILQ_REMOVE(&la->checkExpire, (*lnk), expire.list); + TAILQ_INSERT_TAIL(&la->checkExpire, (*lnk), expire.list); +} + +static struct alias_link * +UseLink(struct libalias *la, struct alias_link *lnk) +{ + CleanupLink(la, &lnk); + if (lnk != NULL) + lnk->timestamp = LibAliasTime; + return (lnk); } static void @@ -849,24 +877,32 @@ ClearFWHole(lnk); #endif - /* Free memory allocated for LSNAT server pool */ - if (lnk->server != NULL) { - struct server *head, *curr, *next; + switch (lnk->link_type) { + case LINK_PPTP: + LIST_REMOVE(lnk, pptp.list); + break; + default: + /* Free memory allocated for LSNAT server pool */ + if (lnk->server != NULL) { + struct server *head, *curr, *next; + + head = curr = lnk->server; + do { + next = curr->next; + free(curr); + } while ((curr = next) != head); + } else { + /* Adjust output table pointers */ + LIST_REMOVE(lnk, all.out); + } - head = curr = lnk->server; - do { - next = curr->next; - free(curr); - } while ((curr = next) != head); + /* Adjust input table pointers */ + LIST_REMOVE(lnk, all.in); + break; } - /* Adjust output table pointers */ - LIST_REMOVE(lnk, list_out); - - /* Adjust input table pointers */ - LIST_REMOVE(lnk, list_in); /* remove from housekeeping */ - TAILQ_REMOVE(&la->checkExpire, lnk, list_expire); + TAILQ_REMOVE(&la->checkExpire, lnk, expire.list); #ifndef NO_USE_SOCKETS /* Close socket, if one has been allocated */ @@ -924,133 +960,150 @@ struct alias_link *lnk; LIBALIAS_LOCK_ASSERT(la); + lnk = malloc(sizeof(struct alias_link)); - if (lnk != NULL) { - /* Basic initialization */ - lnk->la = la; - lnk->src_addr = src_addr; - lnk->dst_addr = dst_addr; - lnk->alias_addr = alias_addr; - lnk->proxy_addr.s_addr = INADDR_ANY; - lnk->src_port = src_port; - lnk->dst_port = dst_port; - lnk->proxy_port = 0; - lnk->server = NULL; - lnk->link_type = link_type; + if (lnk == NULL) { +#ifdef LIBALIAS_DEBUG + fprintf(stderr, "PacketAlias/AddLink(): "); + fprintf(stderr, "malloc() call failed.\n"); +#endif + return (NULL); + } + /* Basic initialization */ + lnk->la = la; + lnk->src_addr = src_addr; + lnk->dst_addr = dst_addr; + lnk->alias_addr = alias_addr; + lnk->proxy_addr.s_addr = INADDR_ANY; + lnk->src_port = src_port; + lnk->dst_port = dst_port; + lnk->proxy_port = 0; + lnk->server = NULL; + lnk->link_type = link_type; #ifndef NO_USE_SOCKETS - lnk->sockfd = -1; + lnk->sockfd = -1; #endif - lnk->flags = 0; - lnk->pflags = 0; - lnk->timestamp = LibAliasTime; + lnk->flags = 0; + lnk->pflags = 0; + lnk->timestamp = LibAliasTime; - /* Expiration time */ - switch (link_type) { - case LINK_ICMP: - lnk->expire_time = ICMP_EXPIRE_TIME; - break; - case LINK_UDP: - lnk->expire_time = UDP_EXPIRE_TIME; - break; - case LINK_TCP: - lnk->expire_time = TCP_EXPIRE_INITIAL; - break; - case LINK_PPTP: - lnk->flags |= LINK_PERMANENT; /* no timeout. */ - break; - case LINK_FRAGMENT_ID: - lnk->expire_time = FRAGMENT_ID_EXPIRE_TIME; - break; - case LINK_FRAGMENT_PTR: - lnk->expire_time = FRAGMENT_PTR_EXPIRE_TIME; - break; - case LINK_ADDR: - break; - default: - lnk->expire_time = PROTO_EXPIRE_TIME; - break; - } + /* Expiration time */ + switch (link_type) { + case LINK_ICMP: + lnk->expire.timeout = ICMP_EXPIRE_TIME; + break; + case LINK_UDP: + lnk->expire.timeout = UDP_EXPIRE_TIME; + break; + case LINK_TCP: + lnk->expire.timeout = TCP_EXPIRE_INITIAL; + break; + case LINK_FRAGMENT_ID: + lnk->expire.timeout = FRAGMENT_ID_EXPIRE_TIME; + break; + case LINK_FRAGMENT_PTR: + lnk->expire.timeout = FRAGMENT_PTR_EXPIRE_TIME; + break; + case LINK_ADDR: + break; + default: + lnk->expire.timeout = PROTO_EXPIRE_TIME; + break; + } + + /* Determine alias flags */ + if (dst_addr.s_addr == INADDR_ANY) + lnk->flags |= LINK_UNKNOWN_DEST_ADDR; + if (dst_port == 0) + lnk->flags |= LINK_UNKNOWN_DEST_PORT; - /* Determine alias flags */ - if (dst_addr.s_addr == INADDR_ANY) - lnk->flags |= LINK_UNKNOWN_DEST_ADDR; - if (dst_port == 0) - lnk->flags |= LINK_UNKNOWN_DEST_PORT; + /* Determine alias port */ + if (GetNewPort(la, lnk, alias_port_param) != 0) { + free(lnk); + return (NULL); + } + /* Link-type dependent initialization */ + switch (link_type) { + case LINK_ICMP: + la->icmpLinkCount++; + break; + case LINK_UDP: + la->udpLinkCount++; + break; + case LINK_TCP: { + struct tcp_dat *aux_tcp; + int i; - /* Determine alias port */ - if (GetNewPort(la, lnk, alias_port_param) != 0) { + aux_tcp = malloc(sizeof(struct tcp_dat)); + if (aux_tcp != NULL) { +#ifdef LIBALIAS_DEBUG + fprintf(stderr, "PacketAlias/AddLink: "); + fprintf(stderr, " cannot allocate auxiliary TCP data\n"); +#endif free(lnk); return (NULL); } - /* Link-type dependent initialization */ - switch (link_type) { - struct tcp_dat *aux_tcp; - case LINK_ICMP: - la->icmpLinkCount++; - break; - case LINK_UDP: - la->udpLinkCount++; - break; - case LINK_TCP: - aux_tcp = malloc(sizeof(struct tcp_dat)); - if (aux_tcp != NULL) { - int i; - - la->tcpLinkCount++; - aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED; - aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED; - aux_tcp->state.index = 0; - aux_tcp->state.ack_modified = 0; - for (i = 0; i < N_LINK_TCP_DATA; i++) - aux_tcp->ack[i].active = 0; - aux_tcp->fwhole = -1; - lnk->data.tcp = aux_tcp; - } else { -#ifdef LIBALIAS_DEBUG - fprintf(stderr, "PacketAlias/AddLink: "); - fprintf(stderr, " cannot allocate auxiliary TCP data\n"); -#endif - free(lnk); - return (NULL); - } - break; - case LINK_PPTP: - la->pptpLinkCount++; - break; - case LINK_FRAGMENT_ID: - la->fragmentIdLinkCount++; - break; - case LINK_FRAGMENT_PTR: - la->fragmentPtrLinkCount++; - break; - case LINK_ADDR: - break; - default: - la->protoLinkCount++; - break; + la->tcpLinkCount++; + aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED; + aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED; + aux_tcp->state.index = 0; + aux_tcp->state.ack_modified = 0; + for (i = 0; i < N_LINK_TCP_DATA; i++) + aux_tcp->ack[i].active = 0; + aux_tcp->fwhole = -1; + lnk->data.tcp = aux_tcp; + } + break; + case LINK_PPTP: + la->pptpLinkCount++; + break; + case LINK_FRAGMENT_ID: + la->fragmentIdLinkCount++; + break; + case LINK_FRAGMENT_PTR: + la->fragmentPtrLinkCount++; + break; + case LINK_ADDR: + break; + default: + la->protoLinkCount++; + break; + } + + switch (link_type) { + case LINK_PPTP: + LIST_INSERT_HEAD(&la->pptpList, lnk, pptp.list); + break; + default: { + struct group_in *grp; + + grp = StartPointIn(la, alias_addr, lnk->alias_port, link_type, 1); + if (grp == NULL) { + free(lnk); + return (NULL); } /* Set up pointers for output lookup table */ start_point = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type); - LIST_INSERT_HEAD(&la->linkTableOut[start_point], lnk, list_out); + LIST_INSERT_HEAD(&la->linkTableOut[start_point], lnk, all.out); /* Set up pointers for input lookup table */ - start_point = StartPointIn(alias_addr, lnk->alias_port, link_type); - LIST_INSERT_HEAD(&la->linkTableIn[start_point], lnk, list_in); - - /* Include the element into the housekeeping list */ - TAILQ_INSERT_TAIL(&la->checkExpire, lnk, list_expire); - } else { -#ifdef LIBALIAS_DEBUG - fprintf(stderr, "PacketAlias/AddLink(): "); - fprintf(stderr, "malloc() call failed.\n"); -#endif + if (lnk->flags & LINK_PARTIALLY_SPECIFIED) + LIST_INSERT_HEAD(&grp->partial, lnk, all.in); + else + LIST_INSERT_HEAD(&grp->full, lnk, all.in); } - if (la->packetAliasMode & PKT_ALIAS_LOG) { - ShowAliasStats(la); + break; } + + /* Include the element into the housekeeping list */ + TAILQ_INSERT_TAIL(&la->checkExpire, lnk, expire.list); + + if (la->packetAliasMode & PKT_ALIAS_LOG) + ShowAliasStats(la); + return (lnk); } @@ -1086,6 +1139,35 @@ return (new_lnk); } + +#define OUTGUARD \ + if (lnk->src_port != src_port || \ + lnk->src_addr.s_addr != src_addr.s_addr || \ + lnk->dst_addr.s_addr != dst_addr.s_addr || \ + lnk->dst_port != dst_port || \ + lnk->link_type != link_type) \ + continue; + +static struct alias_link * +_SearchLinkOut(struct libalias *la, struct in_addr src_addr, + struct in_addr dst_addr, + u_short src_port, + u_short dst_port, + int link_type) { + u_int i; + struct alias_link *lnk; + + i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type); + LIST_FOREACH(lnk, &la->linkTableOut[i], all.out) { + OUTGUARD; + return (UseLink(la, lnk)); + } + + return (NULL); +} + +#undef OUTGUARD + static struct alias_link * _FindLinkOut(struct libalias *la, struct in_addr src_addr, struct in_addr dst_addr, @@ -1094,45 +1176,31 @@ int link_type, int replace_partial_links) { - u_int i; struct alias_link *lnk; LIBALIAS_LOCK_ASSERT(la); - i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type); - LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) { - if (lnk->dst_addr.s_addr == dst_addr.s_addr && - lnk->src_addr.s_addr == src_addr.s_addr && - lnk->src_port == src_port && - lnk->dst_port == dst_port && - lnk->link_type == link_type && - lnk->server == NULL) - break; - } - - CleanupLink(la, &lnk); - if (lnk != NULL) - lnk->timestamp = LibAliasTime; + lnk = _SearchLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type); + if (lnk != NULL || !replace_partial_links) + return (lnk); /* Search for partially specified links. */ - if (lnk == NULL && replace_partial_links) { - if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) { - lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, 0, - link_type, 0); - if (lnk == NULL) - lnk = _FindLinkOut(la, src_addr, NO_ADDR, src_port, - dst_port, link_type, 0); - } - if (lnk == NULL && - (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) { - lnk = _FindLinkOut(la, src_addr, NO_ADDR, src_port, 0, - link_type, 0); - } - if (lnk != NULL) { - lnk = ReLink(lnk, - src_addr, dst_addr, lnk->alias_addr, - src_port, dst_port, lnk->alias_port, - link_type); - } + if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) { + lnk = _SearchLinkOut(la, src_addr, dst_addr, src_port, 0, + link_type); + if (lnk == NULL) + lnk = _SearchLinkOut(la, src_addr, ANY_ADDR, src_port, + dst_port, link_type); + } + if (lnk == NULL && + (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) { + lnk = _SearchLinkOut(la, src_addr, ANY_ADDR, src_port, 0, + link_type); + } + if (lnk != NULL) { + lnk = ReLink(lnk, + src_addr, dst_addr, lnk->alias_addr, + src_port, dst_port, lnk->alias_port, + link_type); } return (lnk); } @@ -1160,7 +1228,7 @@ */ if (la->aliasAddress.s_addr != INADDR_ANY && src_addr.s_addr == la->aliasAddress.s_addr) { - lnk = _FindLinkOut(la, NO_ADDR, dst_addr, src_port, dst_port, + lnk = _FindLinkOut(la, ANY_ADDR, dst_addr, src_port, dst_port, link_type, replace_partial_links); } } @@ -1176,16 +1244,16 @@ int replace_partial_links) { int flags_in; - u_int start_point; + struct group_in *grp; struct alias_link *lnk; - struct alias_link *lnk_fully_specified; struct alias_link *lnk_unknown_all; struct alias_link *lnk_unknown_dst_addr; struct alias_link *lnk_unknown_dst_port; + struct in_addr src_addr; + u_short src_port; LIBALIAS_LOCK_ASSERT(la); /* Initialize pointers */ - lnk_fully_specified = NULL; lnk_unknown_all = NULL; lnk_unknown_dst_addr = NULL; lnk_unknown_dst_port = NULL; @@ -1199,79 +1267,78 @@ flags_in |= LINK_UNKNOWN_DEST_PORT; /* Search loop */ - start_point = StartPointIn(alias_addr, alias_port, link_type); - LIST_FOREACH(lnk, &la->linkTableIn[start_point], list_in) { - int flags; - - flags = flags_in | lnk->flags; - if (!(flags & LINK_PARTIALLY_SPECIFIED)) { - if (lnk->alias_addr.s_addr == alias_addr.s_addr - && lnk->alias_port == alias_port - && lnk->dst_addr.s_addr == dst_addr.s_addr - && lnk->dst_port == dst_port - && lnk->link_type == link_type) { - lnk_fully_specified = lnk; + grp = StartPointIn(la, alias_addr, alias_port, link_type, 0); + if (grp == NULL) + return (NULL); + + switch (flags_in) { + case 0: + LIST_FOREACH(lnk, &grp->full, all.in) { + if (lnk->dst_addr.s_addr == dst_addr.s_addr && + lnk->dst_port == dst_port) + return (UseLink(la, lnk)); + } + break; + case LINK_UNKNOWN_DEST_PORT: + LIST_FOREACH(lnk, &grp->full, all.in) { + if(lnk->dst_addr.s_addr == dst_addr.s_addr) { + lnk_unknown_dst_port = lnk; break; } - } else if ((flags & LINK_UNKNOWN_DEST_ADDR) - && (flags & LINK_UNKNOWN_DEST_PORT)) { - if (lnk->alias_addr.s_addr == alias_addr.s_addr - && lnk->alias_port == alias_port - && lnk->link_type == link_type) { - if (lnk_unknown_all == NULL) - lnk_unknown_all = lnk; - } - } else if (flags & LINK_UNKNOWN_DEST_ADDR) { - if (lnk->alias_addr.s_addr == alias_addr.s_addr - && lnk->alias_port == alias_port - && lnk->link_type == link_type - && lnk->dst_port == dst_port) { - if (lnk_unknown_dst_addr == NULL) - lnk_unknown_dst_addr = lnk; + } + break; + case LINK_UNKNOWN_DEST_ADDR: + LIST_FOREACH(lnk, &grp->full, all.in) { + if(lnk->dst_port == dst_port) { + lnk_unknown_dst_addr = lnk; + break; } - } else if (flags & LINK_UNKNOWN_DEST_PORT) { - if (lnk->alias_addr.s_addr == alias_addr.s_addr - && lnk->alias_port == alias_port - && lnk->link_type == link_type - && lnk->dst_addr.s_addr == dst_addr.s_addr) { - if (lnk_unknown_dst_port == NULL) - lnk_unknown_dst_port = lnk; + } + break; + case LINK_PARTIALLY_SPECIFIED: + lnk_unknown_all = LIST_FIRST(&grp->full); + break; + } + + if (lnk_unknown_dst_port == NULL) { + LIST_FOREACH(lnk, &grp->partial, all.in) { + int flags = (flags_in | lnk->flags) & LINK_PARTIALLY_SPECIFIED; + + if (flags == LINK_PARTIALLY_SPECIFIED && + lnk_unknown_all == NULL) + lnk_unknown_all = lnk; + if (flags == LINK_UNKNOWN_DEST_ADDR && + lnk->dst_port == dst_port && + lnk_unknown_dst_addr == NULL) + lnk_unknown_dst_addr = lnk; + if (flags == LINK_UNKNOWN_DEST_PORT && + lnk->dst_addr.s_addr == dst_addr.s_addr) { + lnk_unknown_dst_port = lnk; + break; } } } - CleanupLink(la, &lnk_fully_specified); - if (lnk_fully_specified != NULL) { - lnk_fully_specified->timestamp = LibAliasTime; - lnk = lnk_fully_specified; - } else if (lnk_unknown_dst_port != NULL) - lnk = lnk_unknown_dst_port; - else if (lnk_unknown_dst_addr != NULL) - lnk = lnk_unknown_dst_addr; - else if (lnk_unknown_all != NULL) - lnk = lnk_unknown_all; - else - return (NULL); + lnk = (lnk_unknown_dst_port != NULL) ? lnk_unknown_dst_port + : (lnk_unknown_dst_addr != NULL) ? lnk_unknown_dst_addr + : lnk_unknown_all; - if (replace_partial_links && - (lnk->flags & LINK_PARTIALLY_SPECIFIED || lnk->server != NULL)) { - struct in_addr src_addr; - u_short src_port; + if (lnk == NULL || !replace_partial_links) + return (lnk); - if (lnk->server != NULL) { /* LSNAT link */ - src_addr = lnk->server->addr; - src_port = lnk->server->port; - lnk->server = lnk->server->next; - } else { - src_addr = lnk->src_addr; - src_port = lnk->src_port; - } + if (lnk->server != NULL) { /* LSNAT link */ + src_addr = lnk->server->addr; + src_port = lnk->server->port; + lnk->server = lnk->server->next; + } else { + src_addr = lnk->src_addr; + src_port = lnk->src_port; + } - if (link_type == LINK_SCTP) { - lnk->src_addr = src_addr; - lnk->src_port = src_port; - return (lnk); - } + if (link_type == LINK_SCTP) { + lnk->src_addr = src_addr; + lnk->src_port = src_port; + } else { lnk = ReLink(lnk, src_addr, dst_addr, alias_addr, src_port, dst_port, alias_port, @@ -1303,7 +1370,7 @@ */ if (la->aliasAddress.s_addr != INADDR_ANY && alias_addr.s_addr == la->aliasAddress.s_addr) { - lnk = _FindLinkIn(la, dst_addr, NO_ADDR, dst_port, alias_port, + lnk = _FindLinkIn(la, dst_addr, ANY_ADDR, dst_port, alias_port, link_type, replace_partial_links); } } @@ -1385,7 +1452,7 @@ LINK_FRAGMENT_ID, 0); if (lnk == NULL) { - lnk = AddLink(la, NO_ADDR, dst_addr, alias_addr, + lnk = AddLink(la, ANY_ADDR, dst_addr, alias_addr, NO_SRC_PORT, NO_DEST_PORT, ip_id, LINK_FRAGMENT_ID); } @@ -1408,7 +1475,7 @@ u_short ip_id) { LIBALIAS_LOCK_ASSERT(la); - return AddLink(la, NO_ADDR, dst_addr, NO_ADDR, + return AddLink(la, ANY_ADDR, dst_addr, ANY_ADDR, NO_SRC_PORT, NO_DEST_PORT, ip_id, LINK_FRAGMENT_PTR); } @@ -1418,7 +1485,7 @@ u_short ip_id) { LIBALIAS_LOCK_ASSERT(la); - return FindLinkIn(la, dst_addr, NO_ADDR, + return FindLinkIn(la, dst_addr, ANY_ADDR, NO_DEST_PORT, ip_id, LINK_FRAGMENT_PTR, 0); } @@ -1566,20 +1633,16 @@ struct in_addr dst_addr, u_int16_t src_call_id) { - u_int i; struct alias_link *lnk; LIBALIAS_LOCK_ASSERT(la); - i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP); - LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) - if (lnk->link_type == LINK_PPTP && - lnk->src_addr.s_addr == src_addr.s_addr && + LIST_FOREACH(lnk, &la->pptpList, pptp.list) + if (lnk->src_addr.s_addr == src_addr.s_addr && lnk->dst_addr.s_addr == dst_addr.s_addr && lnk->src_port == src_call_id) break; - CleanupLink(la, &lnk); - return (lnk); + return (UseLink(la, lnk)); } struct alias_link * @@ -1587,20 +1650,16 @@ struct in_addr dst_addr, u_int16_t dst_call_id) { - u_int i; struct alias_link *lnk; LIBALIAS_LOCK_ASSERT(la); - i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP); - LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) - if (lnk->link_type == LINK_PPTP && - lnk->src_addr.s_addr == src_addr.s_addr && + LIST_FOREACH(lnk, &la->pptpList, pptp.list) + if (lnk->src_addr.s_addr == src_addr.s_addr && lnk->dst_addr.s_addr == dst_addr.s_addr && lnk->dst_port == dst_call_id) break; - CleanupLink(la, &lnk); - return (lnk); + return (UseLink(la, lnk)); } struct alias_link * @@ -1608,20 +1667,17 @@ struct in_addr alias_addr, u_int16_t dst_call_id) { - u_int i; struct alias_link *lnk; LIBALIAS_LOCK_ASSERT(la); - i = StartPointIn(alias_addr, 0, LINK_PPTP); - LIST_FOREACH(lnk, &la->linkTableIn[i], list_in) - if (lnk->link_type == LINK_PPTP && + + LIST_FOREACH(lnk, &la->pptpList, pptp.list) + if (lnk->dst_port == dst_call_id && lnk->dst_addr.s_addr == dst_addr.s_addr && - lnk->alias_addr.s_addr == alias_addr.s_addr && - lnk->dst_port == dst_call_id) + lnk->alias_addr.s_addr == alias_addr.s_addr) break; - CleanupLink(la, &lnk); - return (lnk); + return (UseLink(la, lnk)); } struct alias_link * @@ -1632,9 +1688,11 @@ struct alias_link *lnk; LIBALIAS_LOCK_ASSERT(la); - lnk = FindLinkIn(la, dst_addr, alias_addr, - 0 /* any */ , alias_call_id, - LINK_PPTP, 0); + LIST_FOREACH(lnk, &la->pptpList, pptp.list) + if (lnk->alias_port == alias_call_id && + lnk->dst_addr.s_addr == dst_addr.s_addr && + lnk->alias_addr.s_addr == alias_addr.s_addr) + break; return (lnk); } @@ -1681,7 +1739,7 @@ struct alias_link *lnk; LIBALIAS_LOCK_ASSERT(la); - lnk = FindLinkIn(la, NO_ADDR, alias_addr, + lnk = FindLinkIn(la, ANY_ADDR, alias_addr, 0, 0, LINK_ADDR, 0); if (lnk == NULL) { la->newDefaultLink = 1; @@ -1713,7 +1771,7 @@ struct alias_link *lnk; LIBALIAS_LOCK_ASSERT(la); - lnk = FindLinkOut(la, original_addr, NO_ADDR, + lnk = FindLinkOut(la, original_addr, ANY_ADDR, 0, 0, LINK_ADDR, 0); if (lnk == NULL) { return (la->aliasAddress.s_addr != INADDR_ANY) ? @@ -1772,13 +1830,13 @@ switch (state) { case ALIAS_TCP_STATE_DISCONNECTED: if (lnk->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) - lnk->expire_time = TCP_EXPIRE_DEAD; + lnk->expire.timeout = TCP_EXPIRE_DEAD; else - lnk->expire_time = TCP_EXPIRE_SINGLEDEAD; + lnk->expire.timeout = TCP_EXPIRE_SINGLEDEAD; break; case ALIAS_TCP_STATE_CONNECTED: if (lnk->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED) - lnk->expire_time = TCP_EXPIRE_CONNECTED; + lnk->expire.timeout = TCP_EXPIRE_CONNECTED; break; default: #ifdef _KERNEL @@ -1797,13 +1855,13 @@ switch (state) { case ALIAS_TCP_STATE_DISCONNECTED: if (lnk->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) - lnk->expire_time = TCP_EXPIRE_DEAD; + lnk->expire.timeout = TCP_EXPIRE_DEAD; else - lnk->expire_time = TCP_EXPIRE_SINGLEDEAD; + lnk->expire.timeout = TCP_EXPIRE_SINGLEDEAD; break; case ALIAS_TCP_STATE_CONNECTED: if (lnk->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED) - lnk->expire_time = TCP_EXPIRE_CONNECTED; + lnk->expire.timeout = TCP_EXPIRE_CONNECTED; break; default: #ifdef _KERNEL @@ -2052,7 +2110,7 @@ } else if (expire == -1) { lnk->flags |= LINK_PERMANENT; } else if (expire > 0) { - lnk->expire_time = expire; + lnk->expire.timeout = expire; } else { #ifdef LIBALIAS_DEBUG fprintf(stderr, "PacketAlias/SetExpire(): "); @@ -2256,7 +2314,14 @@ LIBALIAS_LOCK(la); (void)la; - server = malloc(sizeof(struct server)); + switch (lnk->link_type) { + case LINK_PPTP: + server = NULL; + break; + default: + server = malloc(sizeof(struct server)); + break; + } if (server != NULL) { struct server *head; @@ -2265,9 +2330,11 @@ server->port = port; head = lnk->server; - if (head == NULL) + if (head == NULL) { server->next = server; - else { + /* not usable for outgoing connections */ + LIST_REMOVE(lnk, all.out); + } else { struct server *s; for (s = head; s->next != head; s = s->next) @@ -2321,7 +2388,7 @@ struct alias_link *lnk; LIBALIAS_LOCK(la); - lnk = AddLink(la, src_addr, NO_ADDR, alias_addr, + lnk = AddLink(la, src_addr, ANY_ADDR, alias_addr, 0, 0, 0, LINK_ADDR); @@ -2439,7 +2506,8 @@ for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) LIST_INIT(&la->linkTableOut[i]); for (i = 0; i < LINK_TABLE_IN_SIZE; i++) - LIST_INIT(&la->linkTableIn[i]); + LIST_INIT(&la->groupTableIn[i]); + LIST_INIT(&la->pptpList); TAILQ_INIT(&la->checkExpire); #ifdef _KERNEL AliasSctpInit(la); @@ -2459,6 +2527,8 @@ la->aliasAddress.s_addr = INADDR_ANY; la->targetAddress.s_addr = INADDR_ANY; + la->aliasPortLower = 0x8000; + la->aliasPortLength = 0x8000; la->icmpLinkCount = 0; la->udpLinkCount = 0; Index: sys/netinet/libalias/alias_local.h =================================================================== --- sys/netinet/libalias/alias_local.h +++ sys/netinet/libalias/alias_local.h @@ -80,6 +80,14 @@ struct proxy_entry; +struct group_in { + struct in_addr alias_addr; + u_short alias_port; + int link_type; + LIST_ENTRY(group_in) group_in; + LIST_HEAD(, alias_link) full, partial; +}; + struct libalias { LIST_ENTRY(libalias) instancelist; /* Mode flags documented in alias.h */ @@ -92,8 +100,9 @@ /* Lookup table of pointers to chains of link records. * Each link record is doubly indexed into input and * output lookup tables. */ - LIST_HEAD (, alias_link) linkTableOut[LINK_TABLE_OUT_SIZE]; - LIST_HEAD (, alias_link) linkTableIn[LINK_TABLE_IN_SIZE]; + LIST_HEAD (, alias_link) linkTableOut[LINK_TABLE_OUT_SIZE]; + LIST_HEAD (, group_in) groupTableIn[LINK_TABLE_IN_SIZE]; + LIST_HEAD (, alias_link) pptpList; /* HouseKeeping */ TAILQ_HEAD (, alias_link) checkExpire; /* Link statistics */