--- /home/bms/fp4/nethead/sys/netinet/in.c 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; --- /home/bms/fp4/nethead/sys/netinet/in_pcb.c 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); --- /home/bms/fp4/nethead/sys/netinet/in_pcb.h 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 *); --- /home/bms/fp4/nethead/sys/netinet/tcp_output.c 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 #include +#include +#include #include #include #include #include #include +#include #include #ifdef INET6 #include @@ -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; } /* --- /home/bms/fp4/nethead/sys/netinet/tcp_usrreq.c 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. */ --- /home/bms/fp4/nethead/sys/netinet/udp_usrreq.c 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);