kern/38554: changing interface ipaddress doesn't seem to work
Bruce M Simpson
bms at incunabulum.net
Sat Sep 23 10:40:25 PDT 2006
The following reply was made to PR kern/38554; it has been noted by GNATS.
From: Bruce M Simpson <bms at incunabulum.net>
To: freebsd-gnats-submit at FreeBSD.org
Cc:
Subject: Re: kern/38554: changing interface ipaddress doesn't seem to work
Date: Sat, 23 Sep 2006 18:35:50 +0100
This is a multi-part message in MIME format.
--------------030000070707080504040106
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Before I suspend my work on this PR, here's a diff I pulled from trying
to port the changes to today's CURRENT.
The patch doesn't work but haven't tested exhaustively. Need to focus on
other things.
--------------030000070707080504040106
Content-Type: text/x-patch;
name="archie-locia-20060923.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="archie-locia-20060923.diff"
==== //depot/user/bms/nethead/sys/netinet/in.c#1 - /home/bms/fp4/nethead/sys/netinet/in.c ====
--- /tmp/tmp.23928.0 Sat Sep 23 18:32:59 2006
+++ /home/bms/fp4/nethead/sys/netinet/in.c Sat Sep 23 17:37:13 2006
@@ -459,6 +459,11 @@
* a routing process they will come back.
*/
in_ifadown(&ia->ia_ifa, 1);
+ /*
+ * Mark the interface address as no longer valid.
+ * Sockets that are bound to it should notice.
+ */
+ ia->ia_ifa.ifa_flags |= RTF_REJECT;
EVENTHANDLER_INVOKE(ifaddr_event, ifp);
error = 0;
break;
==== //depot/user/bms/nethead/sys/netinet/in_pcb.c#1 - /home/bms/fp4/nethead/sys/netinet/in_pcb.c ====
--- /tmp/tmp.23928.1 Sat Sep 23 18:32:59 2006
+++ /home/bms/fp4/nethead/sys/netinet/in_pcb.c Sat Sep 23 18:02:08 2006
@@ -238,14 +238,17 @@
anonport = inp->inp_lport == 0 && (nam == NULL ||
((struct sockaddr_in *)nam)->sin_port == 0);
error = in_pcbbind_setup(inp, nam, &inp->inp_laddr.s_addr,
- &inp->inp_lport, cred);
+ &inp->inp_lport, &inp->inp_locia, cred);
if (error)
return (error);
if (in_pcbinshash(inp) != 0) {
inp->inp_laddr.s_addr = INADDR_ANY;
inp->inp_lport = 0;
+ inp->inp_locia = NULL;
return (EAGAIN);
}
+ if (inp->inp_locia != NULL)
+ IFAREF(&inp->inp_locia->ia_ifa);
if (anonport)
inp->inp_flags |= INP_ANONPORT;
return (0);
@@ -262,12 +265,13 @@
*/
int
in_pcbbind_setup(struct inpcb *inp, struct sockaddr *nam, in_addr_t *laddrp,
- u_short *lportp, struct ucred *cred)
+ u_short *lportp, struct in_ifaddr **iap, struct ucred *cred)
{
struct socket *so = inp->inp_socket;
unsigned short *lastport;
struct sockaddr_in *sin;
struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
+ struct in_ifaddr *ia = NULL;
struct in_addr laddr;
u_short lport = 0;
int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
@@ -319,7 +323,8 @@
} else if (sin->sin_addr.s_addr != INADDR_ANY) {
sin->sin_port = 0; /* yech... */
bzero(&sin->sin_zero, sizeof(sin->sin_zero));
- if (ifa_ifwithaddr((struct sockaddr *)sin) == 0)
+ if ((ia = (struct in_ifaddr *)ifa_ifwithaddr(
+ (struct sockaddr *)sin)) == 0)
return (EADDRNOTAVAIL);
}
laddr = sin->sin_addr;
@@ -478,6 +483,8 @@
return (EINVAL);
*laddrp = laddr.s_addr;
*lportp = lport;
+ if (iap != NULL)
+ *iap = ia;
return (0);
}
@@ -490,6 +497,7 @@
int
in_pcbconnect(struct inpcb *inp, struct sockaddr *nam, struct ucred *cred)
{
+ struct in_ifaddr *locia;
u_short lport, fport;
in_addr_t laddr, faddr;
int anonport, error;
@@ -501,7 +509,7 @@
laddr = inp->inp_laddr.s_addr;
anonport = (lport == 0);
error = in_pcbconnect_setup(inp, nam, &laddr, &lport, &faddr, &fport,
- NULL, cred);
+ NULL, &locia, cred);
if (error)
return (error);
@@ -519,6 +527,9 @@
/* Commit the remaining changes. */
inp->inp_lport = lport;
inp->inp_laddr.s_addr = laddr;
+ inp->inp_locia = locia;
+ if (inp->inp_locia != NULL)
+ IFAREF(&inp->inp_locia->ia_ifa);
inp->inp_faddr.s_addr = faddr;
inp->inp_fport = fport;
in_pcbrehash(inp);
@@ -536,7 +547,9 @@
* On entry, *laddrp and *lportp should contain the current local
* address and port for the PCB; these are updated to the values
* that should be placed in inp_laddr and inp_lport to complete
- * the connect.
+ * the connect. If iap is not NULL, *iap is set to the interface
+ * address corresponding to *laddrp, if any, but no new reference
+ * to it has been added.
*
* On success, *faddrp and *fportp will be set to the remote address
* and port. These are not updated in the error case.
@@ -549,7 +562,7 @@
int
in_pcbconnect_setup(struct inpcb *inp, struct sockaddr *nam,
in_addr_t *laddrp, u_short *lportp, in_addr_t *faddrp, u_short *fportp,
- struct inpcb **oinpp, struct ucred *cred)
+ struct inpcb **oinpp, struct in_ifaddr **iap, struct ucred *cred)
{
struct sockaddr_in *sin = (struct sockaddr_in *)nam;
struct in_ifaddr *ia;
@@ -560,6 +573,7 @@
u_short lport, fport;
int error;
+ ia = NULL;
INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo);
INP_LOCK_ASSERT(inp);
@@ -582,7 +596,7 @@
sa.sin_len = sizeof(sa);
sa.sin_family = AF_INET;
error = in_pcbbind_setup(inp, (struct sockaddr *)&sa,
- &laddr.s_addr, &lport, cred);
+ &laddr.s_addr, &lport, &ia, cred);
if (error)
return (error);
}
@@ -664,7 +678,7 @@
}
if (lport == 0) {
error = in_pcbbind_setup(inp, NULL, &laddr.s_addr, &lport,
- cred);
+ &ia, cred);
if (error)
return (error);
}
@@ -672,6 +686,8 @@
*lportp = lport;
*faddrp = faddr.s_addr;
*fportp = fport;
+ if (iap != NULL)
+ *iap = ia;
return (0);
}
@@ -720,6 +736,8 @@
#endif /*IPSEC*/
inp->inp_gencnt = ++ipi->ipi_gencnt;
in_pcbremlists(inp);
+ if (inp->inp_locia != NULL)
+ IFAFREE(&inp->inp_locia->ia_ifa);
if (inp->inp_options)
(void)m_free(inp->inp_options);
ip_freemoptions(inp->inp_moptions);
==== //depot/user/bms/nethead/sys/netinet/in_pcb.h#1 - /home/bms/fp4/nethead/sys/netinet/in_pcb.h ====
--- /tmp/tmp.23928.2 Sat Sep 23 18:32:59 2006
+++ /home/bms/fp4/nethead/sys/netinet/in_pcb.h Sat Sep 23 17:46:41 2006
@@ -71,6 +71,7 @@
struct in_endpoints {
u_int16_t ie_fport; /* foreign port */
u_int16_t ie_lport; /* local port */
+ struct in_ifaddr *ie_locia; /* locally bound address */
/* protocol dependent part, local and foreign addr */
union {
/* foreign host table entry */
@@ -102,6 +103,7 @@
#define inc_isipv6 inc_flags /* temp compatability */
#define inc_fport inc_ie.ie_fport
#define inc_lport inc_ie.ie_lport
+#define inc_locia inc_ie.ie_locia
#define inc_faddr inc_ie.ie_faddr
#define inc_laddr inc_ie.ie_laddr
#define inc6_faddr inc_ie.ie6_faddr
@@ -145,6 +147,7 @@
} inp_depend4;
#define inp_fport inp_inc.inc_fport
#define inp_lport inp_inc.inc_lport
+#define inp_locia inp_inc.inc_locia
#define inp_faddr inp_inc.inc_faddr
#define inp_laddr inp_inc.inc_laddr
#define inp_ip_tos inp_depend4.inp4_ip_tos
@@ -332,6 +335,8 @@
#define INP_CHECK_SOCKAF(so, af) (INP_SOCKAF(so) == af)
#ifdef _KERNEL
+struct in_ifaddr;
+
extern int ipport_reservedhigh;
extern int ipport_reservedlow;
extern int ipport_lowfirstauto;
@@ -346,11 +351,11 @@
int in_pcballoc(struct socket *, struct inpcbinfo *);
int in_pcbbind(struct inpcb *, struct sockaddr *, struct ucred *);
int in_pcbbind_setup(struct inpcb *, struct sockaddr *, in_addr_t *,
- u_short *, struct ucred *);
+ u_short *, struct in_ifaddr **, struct ucred *);
int in_pcbconnect(struct inpcb *, struct sockaddr *, struct ucred *);
int in_pcbconnect_setup(struct inpcb *, struct sockaddr *, in_addr_t *,
u_short *, in_addr_t *, u_short *, struct inpcb **,
- struct ucred *);
+ struct in_ifaddr **, struct ucred *);
void in_pcbdetach(struct inpcb *);
void in_pcbdisconnect(struct inpcb *);
void in_pcbdrop(struct inpcb *);
==== //depot/user/bms/nethead/sys/netinet/tcp_output.c#1 - /home/bms/fp4/nethead/sys/netinet/tcp_output.c ====
--- /tmp/tmp.23928.3 Sat Sep 23 18:32:59 2006
+++ /home/bms/fp4/nethead/sys/netinet/tcp_output.c Sat Sep 23 17:47:35 2006
@@ -51,12 +51,15 @@
#include <sys/sysctl.h>
#include <net/route.h>
+#include <net/if.h>
+#include <net/if_var.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/in_pcb.h>
#include <netinet/ip_var.h>
+#include <netinet/in_var.h>
#include <netinet/ip_options.h>
#ifdef INET6
#include <netinet6/in6_pcb.h>
@@ -872,6 +875,16 @@
ipov = (struct ipovly *)ip;
th = (struct tcphdr *)(ip + 1);
tcpip_fillheaders(tp->t_inpcb, ip, th);
+ }
+
+ /*
+ * Check that our local (source) IP address is still valid.
+ */
+ if (tp->t_inpcb->inp_locia != NULL
+ && (tp->t_inpcb->inp_locia->ia_ifa.ifa_flags & RTF_REJECT) != 0) {
+ error = EADDRNOTAVAIL;
+ m_freem(m);
+ goto out;
}
/*
==== //depot/user/bms/nethead/sys/netinet/tcp_usrreq.c#1 - /home/bms/fp4/nethead/sys/netinet/tcp_usrreq.c ====
--- /tmp/tmp.23928.4 Sat Sep 23 18:33:00 2006
+++ /home/bms/fp4/nethead/sys/netinet/tcp_usrreq.c Sat Sep 23 17:53:09 2006
@@ -1102,6 +1102,7 @@
{
struct inpcb *inp = tp->t_inpcb, *oinp;
struct socket *so = inp->inp_socket;
+ struct in_ifaddr *locia;
struct in_addr laddr;
u_short lport;
int error;
@@ -1122,13 +1123,20 @@
*/
laddr = inp->inp_laddr;
lport = inp->inp_lport;
+ locia = inp->inp_locia;
error = in_pcbconnect_setup(inp, nam, &laddr.s_addr, &lport,
- &inp->inp_faddr.s_addr, &inp->inp_fport, &oinp, td->td_ucred);
+ &inp->inp_faddr.s_addr, &inp->inp_fport, &oinp, &locia,
+ td->td_ucred);
if (error && oinp == NULL)
return error;
if (oinp)
return EADDRINUSE;
inp->inp_laddr = laddr;
+ if (inp->inp_locia != NULL)
+ IFAFREE(&inp->inp_locia->ia_ifa);
+ inp->inp_locia = locia;
+ if (inp->inp_locia != NULL)
+ IFAREF(&inp->inp_locia->ia_ifa);
in_pcbrehash(inp);
/* Compute window scaling to request. */
==== //depot/user/bms/nethead/sys/netinet/udp_usrreq.c#1 - /home/bms/fp4/nethead/sys/netinet/udp_usrreq.c ====
--- /tmp/tmp.23928.5 Sat Sep 23 18:33:00 2006
+++ /home/bms/fp4/nethead/sys/netinet/udp_usrreq.c Sat Sep 23 17:51:24 2006
@@ -724,6 +724,7 @@
{
register struct udpiphdr *ui;
register int len = m->m_pkthdr.len;
+ struct in_ifaddr *locia;
struct in_addr faddr, laddr;
struct cmsghdr *cm;
struct sockaddr_in *sin, src;
@@ -809,13 +810,14 @@
laddr = inp->inp_laddr;
lport = inp->inp_lport;
+ locia = inp->inp_locia;
if (src.sin_addr.s_addr != INADDR_ANY) {
if (lport == 0) {
error = EINVAL;
goto release;
}
error = in_pcbbind_setup(inp, (struct sockaddr *)&src,
- &laddr.s_addr, &lport, td->td_ucred);
+ &laddr.s_addr, &lport, &locia, td->td_ucred);
if (error)
goto release;
}
@@ -829,7 +831,7 @@
goto release;
}
error = in_pcbconnect_setup(inp, addr, &laddr.s_addr, &lport,
- &faddr.s_addr, &fport, NULL, td->td_ucred);
+ &faddr.s_addr, &fport, NULL, &locia, td->td_ucred);
if (error)
goto release;
@@ -859,6 +861,14 @@
}
/*
+ * Check that the local (source) IP address is valid.
+ */
+ if (locia != NULL && (locia->ia_ifa.ifa_flags & RTF_REJECT) != 0) {
+ error = EADDRNOTAVAIL;
+ goto release;
+ }
+
+ /*
* Calculate data length and get a mbuf for UDP, IP, and possible
* link-layer headers. Immediate slide the data pointer back forward
* since we won't use that space at this layer.
@@ -1088,6 +1098,10 @@
in_pcbdisconnect(inp);
inp->inp_laddr.s_addr = INADDR_ANY;
+ if (inp->inp_locia != NULL) {
+ IFAFREE(&inp->inp_locia->ia_ifa);
+ inp->inp_locia = NULL;
+ }
SOCK_LOCK(so);
so->so_state &= ~SS_ISCONNECTED; /* XXX */
SOCK_UNLOCK(so);
--------------030000070707080504040106--
More information about the freebsd-net
mailing list