Subject: Code to set the "default" IP address for outgoing connections
To: None <tech-net@netbsd.org>
From: Michael Graff <explorer@flame.org>
List: tech-net
Date: 09/17/1998 00:19:43
I have a machine with multiple ethernets, and a few ifconfig aliases
on the loopback interface. I'd like to set a "default" address for
this machine, so unless an address is specified, packets will appear to
come from one of the aliases.
I have code to do this, and it works against -current. Here are the
diffs. Comments welcome, flames, well, I suppose that's ok too.
--Michael
Index: sys/netinet/in.h
===================================================================
RCS file: /cvsroot/src/sys/netinet/in.h,v
retrieving revision 1.39
diff -u -u -r1.39 in.h
--- in.h 1998/09/14 21:15:56 1.39
+++ in.h 1998/09/17 07:25:47
@@ -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.52
diff -u -u -r1.52 in_pcb.c
--- in_pcb.c 1998/08/02 00:35:31 1.52
+++ in_pcb.c 1998/09/17 07:25:51
@@ -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[ \
@@ -290,6 +291,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))
@@ -332,22 +334,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);
@@ -365,39 +366,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,
@@ -405,8 +421,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.70
diff -u -u -r1.70 ip_input.c
--- ip_input.c 1998/09/09 04:57:18 1.70
+++ ip_input.c 1998/09/17 07:25:57
@@ -1416,6 +1416,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);
}
? usr.sbin/sysctl/ktrace.out
Index: usr.sbin/sysctl/sysctl.c
===================================================================
RCS file: /cvsroot/src/usr.sbin/sysctl/sysctl.c,v
retrieving revision 1.16
diff -u -u -r1.16 sysctl.c
--- sysctl.c 1998/03/11 17:44:02 1.16
+++ sysctl.c 1998/09/17 07:26:14
@@ -68,6 +68,8 @@
#include <netinet/tcp_timer.h>
#include <netinet/tcp_var.h>
+#include <arpa/inet.h>
+
#include <err.h>
#include <ctype.h>
#include <errno.h>
@@ -119,6 +121,7 @@
#define CLOCK 0x00000001
#define BOOTTIME 0x00000002
#define CONSDEV 0x00000004
+#define IP_ADDRESS 0x00000008
int main __P((int, char *[]));
@@ -216,6 +219,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];
@@ -320,10 +324,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);
@@ -368,6 +375,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;
@@ -420,6 +438,13 @@
devname(dev, S_IFCHR));
else
fprintf(stdout, "0x%x\n", dev);
+ return;
+ }
+ if (special & IP_ADDRESS) {
+ struct in_addr ina2 = *(struct in_addr *)newval;
+
+ fprintf(stdout, "%s = %s\n", string, inet_ntoa(ina2));
+
return;
}
switch (type) {