Subject: "default" outgoing address
To: None <tech-kern@netbsd.org>
From: Michael Graff <explorer@flame.org>
List: tech-kern
Date: 02/03/1999 22:00:57
I'd like to commit this soon, if noone has serious objections.
Please comment. :)
In my environment at home and where my primary flame.org machines
live, each machine has a physical IP address (which by and large is
not reachable from the outside world) and a number of aliases. These
aliases are reachable to the outside world.
The physical address of one machine for instance is
kechara.rc.vix.com, with an ifalias of kechara.flame.org. I really
want all outgoing connections (unless bound to a specific port) to
originate from the alias, not the real interface address.
Here is a patch that allows me to:
sysctl -w net.inet.ip.srcaddr=204.152.184.79
to set the default address. Basically, if this value is set (it
defaults to 0.0.0.0, which is treated as "do the old thing") the
sections of code which find the "best" IP address to use based on
which interface the connection is going out on is disabled, and the
value set is used instead.
I'd like to commit this, as I know a few others who would like to use
it as well.
Other than the default address, there are other reasons this is
useful. For one, I have several machines at home, one of which has a
4 port ethernet card. Rather than blowing 4 addresses per
host-to-host port, I can use the private network numbers and make an
exported alias the default. This means I can have 4 addresses to run
3 host-to-host ethernets rather than 12.
Here's the diff, from -current as of a day or two ago:
Index: sys/netinet/in.h
===================================================================
RCS file: /cvsroot/src/sys/netinet/in.h,v
retrieving revision 1.39
diff -u -r1.39 in.h
--- in.h 1998/09/14 21:15:56 1.39
+++ in.h 1999/02/04 03:44:32
@@ -297,7 +297,8 @@
#define IPCTL_ANONPORTMAX 11 /* maximum ephemeral port */
#define IPCTL_MTUDISCTIMEOUT 12 /* allow path MTU discovery */
#define IPCTL_MAXFLOWS 13 /* maximum ip flows allowed */
-#define IPCTL_MAXID 14
+#define IPCTL_SRCADDR 14 /* default source address */
+#define IPCTL_MAXID 15
#define IPCTL_NAMES { \
{ 0, 0 }, \
@@ -314,12 +315,14 @@
{ "anonportmax", CTLTYPE_INT }, \
{ "mtudisctimeout", CTLTYPE_INT }, \
{ "maxflows", CTLTYPE_INT }, \
+ { "srcaddr", CTLTYPE_STRUCT }, \
}
#endif /* !_XOPEN_SOURCE */
#ifdef _KERNEL
extern struct in_addr zeroin_addr;
+extern struct in_addr ip_srcaddr;
int in_broadcast __P((struct in_addr, struct ifnet *));
int in_canforward __P((struct in_addr));
Index: sys/netinet/in_pcb.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/in_pcb.c,v
retrieving revision 1.57
diff -u -r1.57 in_pcb.c
--- in_pcb.c 1998/12/19 02:46:12 1.57
+++ in_pcb.c 1999/02/04 03:44:32
@@ -96,6 +96,7 @@
#include <netinet/ip_var.h>
struct in_addr zeroin_addr;
+struct in_addr ip_srcaddr;
#define INPCBHASH_BIND(table, laddr, lport) \
&(table)->inpt_bindhashtbl[ \
@@ -288,6 +289,7 @@
struct in_ifaddr *ia;
struct sockaddr_in *ifaddr = NULL;
register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
+ struct sockaddr_in lsin;
int error;
if (nam->m_len != sizeof (*sin))
@@ -330,22 +332,21 @@
if (in_nullhost(inp->inp_laddr)) {
register struct route *ro;
- ia = (struct in_ifaddr *)0;
+ ia = NULL;
+
/*
* If route is known or can be allocated now,
* our src addr is taken from the i/f, else punt.
*/
ro = &inp->inp_route;
if (ro->ro_rt &&
- (!in_hosteq(satosin(&ro->ro_dst)->sin_addr,
- sin->sin_addr) ||
- inp->inp_socket->so_options & SO_DONTROUTE)) {
+ (!in_hosteq(satosin(&ro->ro_dst)->sin_addr, sin->sin_addr)
+ || inp->inp_socket->so_options & SO_DONTROUTE)) {
RTFREE(ro->ro_rt);
- ro->ro_rt = (struct rtentry *)0;
+ ro->ro_rt = NULL;
}
if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
- (ro->ro_rt == (struct rtentry *)0 ||
- ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
+ (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL)) {
/* No route yet, so try to acquire one */
ro->ro_dst.sa_family = AF_INET;
ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
@@ -363,39 +364,54 @@
if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK))
ia = ifatoia(ro->ro_rt->rt_ifa);
if (ia == 0) {
- u_int16_t fport = sin->sin_port;
-
- sin->sin_port = 0;
- ia = ifatoia(ifa_ifwithladdr(sintosa(sin)));
- sin->sin_port = fport;
- if (ia == 0)
- /* Find 1st non-loopback AF_INET address */
- for (ia = in_ifaddr.tqh_first ; ia != NULL ;
- ia = ia->ia_list.tqe_next)
- if (!(ia->ia_ifp->if_flags & IFF_LOOPBACK))
- break;
- if (ia == 0)
- return (EADDRNOTAVAIL);
+ u_int16_t fport = sin->sin_port;
+ sin->sin_port = 0;
+ ia = ifatoia(ifa_ifwithladdr(sintosa(sin)));
+ sin->sin_port = fport;
+ if (ia == 0)
+ /* Find 1st non-loopback AF_INET address */
+ for (ia = in_ifaddr.tqh_first ; ia != NULL ;
+ ia = ia->ia_list.tqe_next)
+ if (!(ia->ia_ifp->if_flags & IFF_LOOPBACK))
+ break;
+ if (ia == 0)
+ return (EADDRNOTAVAIL);
}
/*
- * If the destination address is multicast and an outgoing
- * interface has been set as a multicast option, use the
- * address of that interface as our source address.
+ * If the destination address is multicast and an
+ * outgoing interface has been set as a multicast
+ * option, use the address of that interface as
+ * our source address.
*/
if (IN_MULTICAST(sin->sin_addr.s_addr) &&
inp->inp_moptions != NULL) {
struct ip_moptions *imo;
struct ifnet *ifp;
-
imo = inp->inp_moptions;
if (imo->imo_multicast_ifp != NULL) {
ifp = imo->imo_multicast_ifp;
- IFP_TO_IA(ifp, ia); /* XXX */
+ IFP_TO_IA(ifp, ia); /* XXX */
if (ia == 0)
return (EADDRNOTAVAIL);
}
}
+
ifaddr = satosin(&ia->ia_addr);
+
+#if 0
+ printf("src 1 %08x:%d dst %08x:%d, route %08x\n",
+ (u_int32_t)inp->inp_laddr.s_addr, ntohs(inp->inp_lport),
+ sin->sin_addr.s_addr, ntohs(sin->sin_port),
+ ifaddr->sin_addr.s_addr);
+#endif
+
+ if ((in_nullhost(ip_srcaddr) == 0)
+ && (sin->sin_addr.s_addr != INADDR_LOOPBACK)
+ && (sin->sin_addr.s_addr != INADDR_ANY)) {
+ lsin.sin_addr = ip_srcaddr;
+ lsin.sin_port = 0;
+ ifaddr = &lsin;
+ }
}
if (in_pcblookup_connect(inp->inp_table, sin->sin_addr, sin->sin_port,
!in_nullhost(inp->inp_laddr) ? inp->inp_laddr : ifaddr->sin_addr,
@@ -403,8 +419,7 @@
return (EADDRINUSE);
if (in_nullhost(inp->inp_laddr)) {
if (inp->inp_lport == 0) {
- error = in_pcbbind(inp, (struct mbuf *)0,
- (struct proc *)0);
+ error = in_pcbbind(inp, NULL, NULL);
/*
* This used to ignore the return value
* completely, but we need to check for
Index: sys/netinet/ip_input.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/ip_input.c,v
retrieving revision 1.80
diff -u -r1.80 ip_input.c
--- ip_input.c 1999/01/19 23:39:57 1.80
+++ ip_input.c 1999/02/04 03:44:33
@@ -1498,6 +1498,46 @@
return (error);
}
#endif
+ case IPCTL_SRCADDR: {
+ struct sockaddr_in sin;
+ int s;
+
+ sin.sin_addr = ip_srcaddr;
+
+ error = sysctl_struct(oldp, oldlenp, newp, newlen,
+ &sin.sin_addr, sizeof(sin.sin_addr));
+
+ if (error)
+ return (error);
+
+ s = splsoftnet();
+
+ /*
+ * setting this to 0.0.0.0 will make the normal look-for-iface
+ * logic work again, so allow that.
+ */
+ if (in_nullhost(sin.sin_addr)) {
+ ip_srcaddr = sin.sin_addr;
+ splx(s);
+ return (0);
+ }
+
+#if 0
+ /*
+ * search for an interface with this address
+ */
+ if (ifa_ifwithladdr(sintosa(&sin)) == NULL) {
+ splx(s);
+ return (EADDRNOTAVAIL);
+ }
+#endif
+
+ ip_srcaddr = sin.sin_addr;
+ splx(s);
+
+ return (0);
+ }
+
default:
return (EOPNOTSUPP);
}
Index: usr.sbin/sysctl/sysctl.c
===================================================================
RCS file: /cvsroot/src/usr.sbin/sysctl/sysctl.c,v
retrieving revision 1.18
diff -u -r1.18 sysctl.c
--- sysctl.c 1998/11/13 20:56:21 1.18
+++ sysctl.c 1999/02/04 03:45:12
@@ -78,6 +78,8 @@
#include <netinet/tcp_timer.h>
#include <netinet/tcp_var.h>
+#include <arpa/inet.h>
+
#include <err.h>
#include <ctype.h>
#include <errno.h>
@@ -130,6 +132,7 @@
#define CLOCK 0x00000001
#define BOOTTIME 0x00000002
#define CONSDEV 0x00000004
+#define IP_ADDRESS 0x00000008
int main __P((int, char *[]));
@@ -229,6 +232,7 @@
void *newval = 0;
int intval, newsize = 0;
quad_t quadval;
+ struct in_addr ina;
size_t size;
struct list *lp;
int mib[CTL_MAXNAME];
@@ -333,10 +337,13 @@
case CTL_NET:
if (mib[1] == PF_INET) {
len = sysctl_inet(string, &bufp, mib, flags, &type);
+ if (len == 4 && mib[2] == IPPROTO_IP && mib[3] == IPCTL_SRCADDR)
+ special |= IP_ADDRESS;
if (len >= 0)
break;
return;
}
+
if (flags == 0)
return;
warnx("Use netstat to view %s information", string);
@@ -397,6 +404,17 @@
newval = &quadval;
newsize = sizeof quadval;
break;
+
+ case CTLTYPE_STRUCT:
+ if (special & IP_ADDRESS) {
+ if (inet_aton(newval, &ina) == 0)
+ errx(1, "Invalid IP address %s",
+ (char *)newval);
+
+ newval = &ina;
+ newsize = sizeof(ina);
+ }
+ break;
}
}
size = BUFSIZ;
@@ -449,6 +467,28 @@
devname(dev, S_IFCHR));
else
fprintf(stdout, "0x%x\n", dev);
+ return;
+ }
+ if (special & IP_ADDRESS) {
+ struct in_addr ina2;
+ char *ina2_s;
+
+ if (newsize == 0) {
+ if (!nflag)
+ fprintf(stdout, "%s = ", string);
+ ina2 = *(struct in_addr *)buf;
+ ina2_s = inet_ntoa(ina2);
+ fprintf(stdout, "%s\n", ina2_s);
+ } else {
+ ina2 = *(struct in_addr *)buf;
+ ina2_s = inet_ntoa(ina2);
+ fprintf(stdout, "%s: %s -> ", string, ina2_s);
+
+ ina2 = *(struct in_addr *)newval;
+ ina2_s = inet_ntoa(ina2);
+ fprintf(stdout, "%s\n", ina2_s);
+ }
+
return;
}
switch (type) {