Date: Mon, 7 Jun 1999 13:37:08 GMT From: fanf@demon.net To: FreeBSD-gnats-submit@freebsd.org Subject: kern/12071: [PATCH] large scale IP aliasing Message-ID: <199906071337.NAA32673@shirt.www.demon.net>
next in thread | raw e-mail | index | archive | help
>Number: 12071 >Category: kern >Synopsis: [PATCH] large scale IP aliasing >Confidential: no >Severity: non-critical >Priority: medium >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: change-request >Submitter-Id: current-users >Arrival-Date: Mon Jun 7 06:40:00 PDT 1999 >Closed-Date: >Last-Modified: >Originator: Tony Finch >Release: FreeBSD 3.2-STABLE-19990601 i386 >Organization: Demon Internet Ltd. >Environment: patch applies to versions of FreeBSD since 3.1 >Description: The NETALIAS patch makes it feasible to have a very large number of IP addresses on one box by making it possible to configure a CIDR network block onto an interface in one go. The additional NETBIND feature allows a program to bind a socket to one of these network aliases. The patch should be applied to a FreeBSD system with the command patch -p0 < netalias-netbind.patch You need to add ``options NETALIAS'' and ``options NETBIND'' to the kernel configuration file and recompile the kernel. You also need to recompile any userland utilities that depend on struct inpcb, in particular systat, netstat, and fstat (and also ipfilter). This can be done with (for example) cd /usr/src/usr.bin/systat make all install clean This must be done even if you only use the NETALIAS functionality because struct inpcb is changed unconditionally. You don't need to do any special compile-time definitions. After rebooting, network aliases can be configured as follows: ifconfig lo0 inet 192.168.0.0 netmask 255.255.0.0 alias Commentary: The NETALIAS patch has four components: (1) A change to ifa_ifwithaddr() in net/if.c that allows an address to match an alias on an interface if the alias is a network address (i.e. zero outside the netmask) and the address is within the network (i.e. equal to the alias when masked by the netmask). (2) A change to netinet/ip_input.c that allows destination addresses on input packets to match a netaliased interface. (This is simpler than the change to if.c because it does not nead to deal with the general form of struct sockaddr.) (3) A similar change to icmp_reflect() in netinet/ip_icmp.c that makes ping work with netalias. (4) A couple of changes to netinet/in.c that makes the automatic addition and deletion of routes work by loosening the assumption that all aliases on the loopback interface only need host routes. (We usually bring up the netaliases on the loopback interface to avoid problems with ARP. XXX: Does ARP work at all with a netaliased physical interface?) The first three parts were originally implemented by Ronald Khoo <ronald@demon.net> for NetBSD 1.0. The latter change was added by me for cosmetic reasons when I ported the changes to FreeBSD 3.0. The NETBIND patch has three components: (1) A change to struct inpcb in netinet/in_pcb.h so that it includes a netmask. It is initialised to INADDR_BROADCAST (i.e. 0xFFFFFFFF) in in_pcballoc() in netinet/in_pcb.c. [Note that /usr/src/sys/netinet/in_pcb.h must be installed into /usr/include/netinet/in_pcb.h, and that netstat, systat, and fstat must all be recompiled so that they know of the change to the struct inpcb.] (2) When an address is bound to a socket, in_pcbbind() in netinet/in_pcb.c checks if the interface address is a netalias, and if so it copies the netmask into the protocol control block. (3) When a protocol control block corresponding to an incoming packet is looked up, in_pcblookup_hash() only checks for a match within the netmask. (This is normally the same as complete equality because of the default netmask, but matches any address in the network for a netbound socket.) The NETBIND functionality was implemented by me. >How-To-Repeat: >Fix: --- /usr/src/sys/conf/options.orig Mon Feb 8 19:05:55 1999 +++ /usr/src/sys/conf/options Thu Feb 18 01:40:13 1999 @@ -334,3 +334,7 @@ # Include LKM compatability module LKM + +# Demon virtual hosting hacks +NETALIAS +NETBIND --- /usr/src/sys/net/if.c.orig Wed Dec 16 18:30:42 1998 +++ /usr/src/sys/net/if.c Thu Feb 18 01:39:34 1999 @@ -35,6 +35,7 @@ */ #include "opt_compat.h" +#include "opt_netalias.h" #include <sys/param.h> #include <sys/malloc.h> @@ -193,6 +194,26 @@ ifa = ifa->ifa_link.tqe_next) { if (ifa->ifa_addr->sa_family != addr->sa_family) continue; +#ifdef NETALIAS + if (ifa->ifa_netmask) { + register char *argaddr, *ifaddr, *mask, *maskend; + /* check to see that the part of the address outside the + * netmask is zero (i.e. it's a network rather than a host) + * and that the addresses are equal within the netmask... + * (see also ifa_ifwithnet() but I prefer these variable names) + */ + argaddr = addr->sa_data; + ifaddr = ifa->ifa_addr->sa_data; + mask = ifa->ifa_netmask->sa_data; + maskend = (char *)ifa->ifa_netmask + ifa->ifa_netmask->sa_len; + for (; mask < maskend; argaddr++, ifaddr++, mask++) + if ((*ifaddr & ~*mask) || + ((*argaddr ^ *ifaddr) & *mask)) + goto breakout; + return (ifa); + } + breakout: +#endif /* NETALIAS */ if (equal(addr, ifa->ifa_addr)) return (ifa); if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr && --- /usr/src/sys/netinet/in.c.orig Mon Dec 7 05:41:10 1998 +++ /usr/src/sys/netinet/in.c Thu Feb 18 01:39:34 1999 @@ -34,6 +34,8 @@ * $Id: netalias-netbind.patch,v 1.3 1999/02/18 10:04:13 fanf Exp $ */ +#include "opt_netalias.h" + #include <sys/param.h> #include <sys/systm.h> #include <sys/sockio.h> @@ -374,7 +376,13 @@ if ((ia->ia_flags & IFA_ROUTE) == 0) return; +#ifdef NETALIAS + if (ifp->if_flags & IFF_POINTOPOINT || + (ifp->if_flags & IFF_LOOPBACK && + ia->ia_addr.sin_addr.s_addr & ia->ia_sockmask.sin_addr.s_addr)) +#else if (ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT)) +#endif rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); else rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0); @@ -445,6 +453,9 @@ htonl(ia->ia_net | ~ ia->ia_netmask); } else if (ifp->if_flags & IFF_LOOPBACK) { ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr; +#ifdef NETALIAS + if (i & ~ia->ia_subnetmask) +#endif flags |= RTF_HOST; } else if (ifp->if_flags & IFF_POINTOPOINT) { if (ia->ia_dstaddr.sin_family != AF_INET) --- /usr/src/sys/netinet/ip_icmp.c.orig Fri Dec 4 04:21:25 1998 +++ /usr/src/sys/netinet/ip_icmp.c Thu Feb 18 01:39:34 1999 @@ -34,6 +34,8 @@ * $Id: netalias-netbind.patch,v 1.3 1999/02/18 10:04:13 fanf Exp $ */ +#include "opt_netalias.h" + #include <sys/param.h> #include <sys/systm.h> #include <sys/mbuf.h> @@ -545,6 +547,11 @@ * to the incoming interface. */ for (ia = in_ifaddrhead.tqh_first; ia; ia = ia->ia_link.tqe_next) { +#ifdef NETALIAS + if (ntohl(IA_SIN(ia)->sin_addr.s_addr) == ia->ia_subnet && + (ntohl(t.s_addr) & ia->ia_subnetmask) == ia->ia_subnet) + goto t_ok; +#endif /* NETALIAS */ if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr) break; if (ia->ia_ifp && (ia->ia_ifp->if_flags & IFF_BROADCAST) && @@ -562,6 +569,9 @@ if (ia == (struct in_ifaddr *)0) ia = in_ifaddrhead.tqh_first; t = IA_SIN(ia)->sin_addr; +#ifdef NETALIAS + t_ok: +#endif /* NETALIAS */ ip->ip_src = t; ip->ip_ttl = MAXTTL; --- /usr/src/sys/netinet/ip_input.c.orig Tue Jan 12 12:25:00 1999 +++ /usr/src/sys/netinet/ip_input.c Thu Feb 18 01:39:34 1999 @@ -42,6 +42,7 @@ #include "opt_ipdn.h" #include "opt_ipdivert.h" #include "opt_ipfilter.h" +#include "opt_netalias.h" #include <stddef.h> @@ -469,6 +470,17 @@ for (ia = TAILQ_FIRST(&in_ifaddrhead); ia; ia = TAILQ_NEXT(ia, ia_link)) { #define satosin(sa) ((struct sockaddr_in *)(sa)) + +#ifdef NETALIAS +#ifdef notdef + printf("netalias check: iaddr %lx subnet %lx mask %lx dst %lx\n", + IA_SIN(ia)->sin_addr.s_addr, + ia->ia_subnet, ia->ia_subnetmask, ip->ip_dst.s_addr); +#endif + if (ntohl(IA_SIN(ia)->sin_addr.s_addr) == ia->ia_subnet && + (ntohl(ip->ip_dst.s_addr) & ia->ia_subnetmask) == ia->ia_subnet) + goto ours; +#endif /* NETALIAS */ if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr) goto ours; --- /usr/src/sys/netinet/in_pcb.c.orig Mon Dec 7 21:58:00 1998 +++ /usr/src/sys/netinet/in_pcb.c Thu Feb 18 01:42:27 1999 @@ -34,6 +34,8 @@ * $Id: netalias-netbind.patch,v 1.3 1999/02/18 10:04:13 fanf Exp $ */ +#include "opt_netbind.h" + #include <sys/param.h> #include <sys/systm.h> #include <sys/malloc.h> @@ -135,6 +137,9 @@ bzero((caddr_t)inp, sizeof(*inp)); inp->inp_gencnt = ++pcbinfo->ipi_gencnt; inp->inp_pcbinfo = pcbinfo; +#ifdef NETBIND + inp->inp_lmask.s_addr = INADDR_BROADCAST; +#endif inp->inp_socket = so; LIST_INSERT_HEAD(pcbinfo->listhead, inp, inp_list); pcbinfo->ipi_count++; @@ -152,6 +157,7 @@ unsigned short *lastport; struct sockaddr_in *sin; struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; + struct in_ifaddr *ia; u_short lport = 0; int wild = 0, reuseport = (so->so_options & SO_REUSEPORT); int error; @@ -187,8 +193,19 @@ reuseport = SO_REUSEADDR|SO_REUSEPORT; } else if (sin->sin_addr.s_addr != INADDR_ANY) { sin->sin_port = 0; /* yech... */ - if (ifa_ifwithaddr((struct sockaddr *)sin) == 0) + ia = (struct in_ifaddr *) + ifa_ifwithaddr((struct sockaddr *)sin); + if (ia == 0) return (EADDRNOTAVAIL); +#ifdef NETBIND + /* if this socket is a network address then copy the netmask into the PCB */ + if (ntohl(IA_SIN(ia)->sin_addr.s_addr) == ia->ia_subnet) + inp->inp_lmask = ia->ia_sockmask.sin_addr; +#ifdef notdef + log(LOG_DEBUG, "netbind check: in_pcbbind addr %08x mask %08x\n", + sin->sin_addr.s_addr, inp->inp_lmask.s_addr); +#endif +#endif } if (lport) { struct inpcb *t; @@ -797,8 +814,21 @@ for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { if (inp->inp_faddr.s_addr == INADDR_ANY && inp->inp_lport == lport) { +#ifdef NETBIND +#ifdef notdef + if (inp->inp_lmask.s_addr != INADDR_BROADCAST) + log(LOG_DEBUG, + "netbind check: in_pcblookup_hash addr %08x mask %08x options %x\n", + inp->inp_laddr.s_addr, inp->inp_lmask.s_addr, inp->inp_socket->so_options); +#endif + /* allow matches to any address within netmask */ + if ((inp->inp_laddr.s_addr & inp->inp_lmask.s_addr) + == (laddr.s_addr & inp->inp_lmask.s_addr)) + return (inp); +#else if (inp->inp_laddr.s_addr == laddr.s_addr) return (inp); +#endif /* NETBIND */ else if (inp->inp_laddr.s_addr == INADDR_ANY) local_wild = inp; } --- /usr/src/sys/netinet/in_pcb.h.orig Fri May 15 00:00:00 1998 +++ /usr/src/sys/netinet/in_pcb.h Thu Feb 18 01:42:41 1999 @@ -77,6 +77,7 @@ LIST_ENTRY(inpcb) inp_portlist; /* list for this PCB's local port */ struct inpcbport *inp_phd; /* head of this list */ inp_gen_t inp_gencnt; /* generation count of this instance */ + struct in_addr inp_lmask; /* local netmask (NETBIND) */ }; /* * The range of the generation count, as used in this implementation, --- /usr/include/netinet/in_pcb.h.orig Fri May 15 00:00:00 1998 +++ /usr/include/netinet/in_pcb.h Thu Feb 18 01:42:41 1999 @@ -77,6 +77,7 @@ LIST_ENTRY(inpcb) inp_portlist; /* list for this PCB's local port */ struct inpcbport *inp_phd; /* head of this list */ inp_gen_t inp_gencnt; /* generation count of this instance */ + struct in_addr inp_lmask; /* local netmask (NETBIND) */ }; /* * The range of the generation count, as used in this implementation, >Release-Note: >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199906071337.NAA32673>