Date: Fri, 21 Apr 2000 19:39:01 +0300 From: Ruslan Ermilov <ru@FreeBSD.ORG> To: Archie Cobbs <archie@whistle.com>, Ari Suutari <ari@suutari.iki.fi>, Brian Somers <brian@Awfulhak.org>, Charles Mott <cmott@scientech.com>, Eivind Eklund <perhaps@yes.no>, Julian Elischer <julian@elischer.org> Cc: net@FreeBSD.ORG Subject: LSNAT for libalias(3) Message-ID: <20000421193901.B1125@relay.ucb.crimea.ua>
next in thread | raw e-mail | index | archive | help
--Nq2Wo0NMKNjxTN9z Content-Type: text/plain; charset=us-ascii Hi! The following two patches add LSNAT capability (described in RFC 2391) to libalias(3) and natd(8). LSNAT links are created by PacketAliasRedirectPort() and then set up by one or more calls to PacketAliasAddServer(). Each call to PacketAliasAddServer() adds a SERVER:PORT pair to the pool of servers. For every *new* incoming session, the SERVER:PORT pair is chosen from the pool in a round-robin fashion, and a new aliasing link is created. LSNAT links are ignored for outgoing sessions. The following command # natd -n ed1 -lsnat tcp WebPool:http www1:http www2:http www3:http will transparently distribute the HTTP service on WebPool between three servers: www1, www2 and www3. As always, your comments/questions/suggestions are highly appreciated. Cheers, -- Ruslan Ermilov Sysadmin and DBA of the ru@ucb.crimea.ua United Commercial Bank, ru@FreeBSD.org FreeBSD committer, +380.652.247.647 Simferopol, Ukraine http://www.FreeBSD.org The Power To Serve http://www.oracle.com Enabling The Information Age --Nq2Wo0NMKNjxTN9z Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="libalias.patch" Index: alias.h =================================================================== RCS file: /usr/FreeBSD-CVS/src/lib/libalias/alias.h,v retrieving revision 1.14 diff -u -p -r1.14 alias.h --- alias.h 2000/04/18 10:18:20 1.14 +++ alias.h 2000/04/21 15:46:56 @@ -52,6 +52,11 @@ struct alias_link; u_char); extern int + PacketAliasAddServer(struct alias_link *link, + struct in_addr addr, + u_short port); + + extern int PacketAliasPptp(struct in_addr); extern struct alias_link * Index: alias_db.c =================================================================== RCS file: /usr/FreeBSD-CVS/src/lib/libalias/alias_db.c,v retrieving revision 1.27 diff -u -p -r1.27 alias_db.c --- alias_db.c 2000/04/18 10:18:20 1.27 +++ alias_db.c 2000/04/21 15:48:25 @@ -237,6 +237,13 @@ struct tcp_dat int fwhole; /* Which firewall record is used for this hole? */ }; +struct server /* LSNAT server pool (circular list) */ +{ + struct in_addr addr; + u_short port; + struct server *next; +}; + struct alias_link /* Main data structure */ { struct in_addr src_addr; /* Address and port information */ @@ -247,6 +254,7 @@ struct alias_link /* Main u_short dst_port; u_short alias_port; u_short proxy_port; + struct server *server; int link_type; /* Type of link: TCP, UDP, ICMP, PPTP, frag */ @@ -778,6 +786,17 @@ DeleteLink(struct alias_link *link) ClearFWHole(link); #endif +/* Free memory allocated for LSNAT server pool */ + if (link->server != NULL) { + struct server *head, *curr, *next; + + head = curr = link->server; + do { + next = curr->next; + free(curr); + } while ((curr = next) != head); + } + /* Adjust output table pointers */ link_last = link->last_out; link_next = link->next_out; @@ -871,6 +890,7 @@ AddLink(struct in_addr src_addr, link->src_port = src_port; link->dst_port = dst_port; link->proxy_port = 0; + link->server = NULL; link->link_type = link_type; link->sockfd = -1; link->flags = 0; @@ -1044,6 +1064,7 @@ _FindLinkOut(struct in_addr src_addr, while (link != NULL) { if (link->src_addr.s_addr == src_addr.s_addr + && link->server == NULL && link->dst_addr.s_addr == dst_addr.s_addr && link->dst_port == dst_port && link->src_port == src_port @@ -1207,39 +1228,39 @@ _FindLinkIn(struct in_addr dst_addr, if (link_fully_specified != NULL) { link_fully_specified->timestamp = timeStamp; - return link_fully_specified; + link = link_fully_specified; } else if (link_unknown_dst_port != NULL) - { - return replace_partial_links - ? ReLink(link_unknown_dst_port, - link_unknown_dst_port->src_addr, dst_addr, alias_addr, - link_unknown_dst_port->src_port, dst_port, alias_port, - link_type) - : link_unknown_dst_port; - } + link = link_unknown_dst_port; else if (link_unknown_dst_addr != NULL) - { - return replace_partial_links - ? ReLink(link_unknown_dst_addr, - link_unknown_dst_addr->src_addr, dst_addr, alias_addr, - link_unknown_dst_addr->src_port, dst_port, alias_port, - link_type) - : link_unknown_dst_addr; - } + link = link_unknown_dst_addr; else if (link_unknown_all != NULL) - { - return replace_partial_links - ? ReLink(link_unknown_all, - link_unknown_all->src_addr, dst_addr, alias_addr, - link_unknown_all->src_port, dst_port, alias_port, - link_type) - : link_unknown_all; - } + link = link_unknown_all; else + return (NULL); + + if (replace_partial_links && + (link->flags & LINK_PARTIALLY_SPECIFIED || link->server != NULL)) { - return(NULL); + struct in_addr src_addr; + u_short src_port; + + if (link->server != NULL) { /* LSNAT link */ + src_addr = link->server->addr; + src_port = link->server->port; + link->server = link->server->next; + } else { + src_addr = link->src_addr; + src_port = link->src_port; + } + + link = ReLink(link, + src_addr, dst_addr, alias_addr, + src_port, dst_port, alias_port, + link_type); } + + return (link); } static struct alias_link * @@ -2035,6 +2056,7 @@ UninitPacketAliasLog(void) -- "outside world" means other than alias*.c routines -- PacketAliasRedirectPort() + PacketAliasAddServer() PacketAliasRedirectPptp() PacketAliasRedirectAddr() PacketAliasRedirectDelete() @@ -2090,6 +2112,36 @@ PacketAliasRedirectPort(struct in_addr s #endif return link; +} + +/* Add server to the pool of servers */ +int +PacketAliasAddServer(struct alias_link *link, struct in_addr addr, u_short port) +{ + struct server *server; + + server = malloc(sizeof(struct server)); + + if (server != NULL) { + struct server *head; + + server->addr = addr; + server->port = port; + + head = link->server; + if (head == NULL) + server->next = server; + else { + struct server *s; + + for (s = head; s->next != head; s = s->next); + s->next = server; + server->next = head; + } + link->server = server; + return (0); + } else + return (-1); } /* Translate PPTP packets to a machine on the inside --Nq2Wo0NMKNjxTN9z Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="natd.patch" Index: natd.c =================================================================== RCS file: /usr/FreeBSD-CVS/src/sbin/natd/natd.c,v retrieving revision 1.25 diff -u -p -r1.25 natd.c --- natd.c 2000/02/25 11:34:38 1.25 +++ natd.c 2000/04/21 15:49:18 @@ -89,6 +89,7 @@ static void RefreshAddr (int); static void ParseOption (const char* option, const char* parms, int cmdLine); static void ReadConfigFile (const char* fileName); static void SetupPortRedirect (const char* parms); +static void SetupLsNatRedirect (const char* parms); static void SetupAddressRedirect (const char* parms); static void SetupPptpAlias (const char* parms); static void StrToAddr (const char* str, struct in_addr* addr); @@ -857,6 +858,7 @@ enum Option { AliasAddress, InterfaceName, RedirectPort, + LsNat, RedirectAddress, ConfigFile, DynamicMode, @@ -1027,6 +1029,14 @@ static struct OptionInfo optionTable[] = "redirect_port", NULL }, + { LsNat, + 0, + String, + "tcp|udp [public_addr:]public_port local_addr:local_port ...", + "load sharing on a port", + "lsnat", + NULL }, + { RedirectAddress, 0, String, @@ -1196,6 +1206,10 @@ static void ParseOption (const char* opt SetupPortRedirect (strValue); break; + case LsNat: + SetupLsNatRedirect (strValue); + break; + case RedirectAddress: SetupAddressRedirect (strValue); break; @@ -1454,6 +1468,82 @@ void SetupPortRedirect (const char* parm htons(publicPort + i), proto); } +} + +void SetupLsNatRedirect (const char* parms) +{ + char buf[128]; + char* ptr; + struct in_addr localAddr; + struct in_addr publicAddr; + struct in_addr remoteAddr; + port_range portRange; + u_short localPort = 0; + u_short publicPort = 0; + u_short remotePort = 0; + int proto; + char* protoName; + char* separator; + struct alias_link *link; + + strcpy (buf, parms); +/* + * Extract protocol. + */ + protoName = strtok (buf, " \t"); + if (!protoName) + errx (1, "lsnat: missing protocol"); + + proto = StrToProto (protoName); +/* + * Extract public port and optionally address. + */ + ptr = strtok (NULL, " \t"); + if (!ptr) + errx (1, "lsnat: missing public port"); + + separator = strchr (ptr, ':'); + if (separator) { + if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 ) + errx (1, "lsnat: invalid public port range"); + } + else { + publicAddr.s_addr = INADDR_ANY; + if (StrToPortRange (ptr, protoName, &portRange) != 0) + errx (1, "lsnat: invalid public port range"); + } + + publicPort = GETLOPORT(portRange); + + localAddr.s_addr = INADDR_NONE; + localPort = ~0; + + remoteAddr.s_addr = INADDR_ANY; + remotePort = 0; + + link = PacketAliasRedirectPort (localAddr, + htons(localPort), + remoteAddr, + htons(remotePort), + publicAddr, + htons(publicPort), + proto); + if (link == NULL) + errx (1, "lsnat: cannot create link"); +/* + * Extract local address and port. + */ + ptr = strtok (NULL, " \t"); + if (!ptr) + errx (1, "lsnat: missing local address"); + + do { + if (StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0) + errx (1, "lsnat: invalid local port range"); + localPort = GETLOPORT(portRange); + (void)PacketAliasAddServer(link, localAddr, htons(localPort)); + } while ((ptr = strtok (NULL, " \t")) != NULL); + } void SetupAddressRedirect (const char* parms) --Nq2Wo0NMKNjxTN9z-- To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-net" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20000421193901.B1125>