Skip site navigation (1)Skip section navigation (2)
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>