Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/netinet/udp_usrreq.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/netinet/udp_usrreq.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.33 retrieving revision 1.47.6.2 diff -u -p -r1.33 -r1.47.6.2 --- src/sys/netinet/udp_usrreq.c 1996/05/23 17:05:45 1.33 +++ src/sys/netinet/udp_usrreq.c 1999/07/06 11:02:51 1.47.6.2 @@ -1,7 +1,36 @@ -/* $NetBSD: udp_usrreq.c,v 1.33 1996/05/23 17:05:45 mycroft Exp $ */ +/* $NetBSD: udp_usrreq.c,v 1.47.6.2 1999/07/06 11:02:51 itojun Exp $ */ /* - * Copyright (c) 1982, 1986, 1988, 1990, 1993 + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,12 +61,19 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)udp_usrreq.c 8.4 (Berkeley) 1/21/94 + * @(#)udp_usrreq.c 8.6 (Berkeley) 5/23/95 */ +/* MAPPED_ADDR_ENABLE must be revisited */ + +#include "ipkdb.h" + #include #include #include +#ifdef MAPPED_ADDR_ENABLED +#include +#endif /* MAPPED_ADDR_ENABLED */ #include #include #include @@ -64,6 +100,12 @@ #include +#ifdef IPSEC +#include +#include +#include +#endif /*IPSEC*/ + /* * UDP protocol implementation. * Per RFC 768, August, 1980. @@ -74,10 +116,7 @@ int udpcksum = 1; int udpcksum = 0; /* XXX */ #endif -struct sockaddr_in udp_in = { sizeof(udp_in), AF_INET }; - static void udp_notify __P((struct inpcb *, int)); -static struct mbuf *udp_saveopt __P((caddr_t, int, int)); #ifndef UDBHASHSIZE #define UDBHASHSIZE 128 @@ -88,7 +127,7 @@ void udp_init() { - in_pcbinit(&udbtable, udbhashsize); + in_pcbinit(&udbtable, udbhashsize, udbhashsize); } void @@ -100,6 +139,7 @@ udp_input(m, va_alist) va_dcl #endif { + int proto; register struct ip *ip; register struct udphdr *uh; register struct inpcb *inp; @@ -108,9 +148,15 @@ udp_input(m, va_alist) struct ip save_ip; int iphlen; va_list ap; + struct sockaddr_in udpsrc; +#ifdef MAPPED_ADDR_ENABLED + struct sockaddr_in6 mapped; +#endif + struct sockaddr *sa; va_start(ap, m); iphlen = va_arg(ap, int); + proto = va_arg(ap, int); va_end(ap); udpstat.udps_ipackets++; @@ -144,13 +190,12 @@ udp_input(m, va_alist) * If not enough data to reflect UDP length, drop. */ len = ntohs((u_int16_t)uh->uh_ulen); - if (ip->ip_len != len) { - if (len > ip->ip_len) { + if (ip->ip_len != iphlen + len) { + if (ip->ip_len < iphlen + len) { udpstat.udps_badlen++; goto bad; } - m_adj(m, len - ip->ip_len); - /* ip->ip_len = len; */ + m_adj(m, iphlen + len - ip->ip_len); } /* * Save a copy of the IP header in case we want restore it @@ -165,16 +210,25 @@ udp_input(m, va_alist) bzero(((struct ipovly *)ip)->ih_x1, sizeof ((struct ipovly *)ip)->ih_x1); ((struct ipovly *)ip)->ih_len = uh->uh_ulen; - if ((uh->uh_sum = in_cksum(m, len + sizeof (struct ip))) != 0) { + if (in_cksum(m, len + sizeof (struct ip)) != 0) { udpstat.udps_badsum++; m_freem(m); return; } } + /* + * Construct sockaddr format source address. + */ + udpsrc.sin_family = AF_INET; + udpsrc.sin_len = sizeof(struct sockaddr_in); + udpsrc.sin_addr = ip->ip_src; + udpsrc.sin_port = uh->uh_sport; + bzero((caddr_t)udpsrc.sin_zero, sizeof(udpsrc.sin_zero)); + if (IN_MULTICAST(ip->ip_dst.s_addr) || in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) { - struct socket *last; + struct inpcb *last; /* * Deliver a multicast or broadcast datagram to *all* sockets * for which the local and remote addresses and ports match @@ -191,13 +245,11 @@ udp_input(m, va_alist) * fixing the interface. Maybe 4.5BSD will remedy this?) */ + iphlen += sizeof(struct udphdr); /* - * Construct sockaddr format source address. + * KAME note: usually we drop udpiphdr from mbuf here. + * we need udpiphdr for iPsec processing so we do that later. */ - udp_in.sin_port = uh->uh_sport; - udp_in.sin_addr = ip->ip_src; - m->m_len -= sizeof (struct udpiphdr); - m->m_data += sizeof (struct udpiphdr); /* * Locate pcb(s) for datagram. * (Algorithm copied from raw_intr().) @@ -208,14 +260,12 @@ udp_input(m, va_alist) inp = inp->inp_queue.cqe_next) { if (inp->inp_lport != uh->uh_dport) continue; - if (inp->inp_laddr.s_addr != INADDR_ANY) { - if (inp->inp_laddr.s_addr != - ip->ip_dst.s_addr) + if (!in_nullhost(inp->inp_laddr)) { + if (!in_hosteq(inp->inp_laddr, ip->ip_dst)) continue; } - if (inp->inp_faddr.s_addr != INADDR_ANY) { - if (inp->inp_faddr.s_addr != - ip->ip_src.s_addr || + if (!in_nullhost(inp->inp_faddr)) { + if (!in_hosteq(inp->inp_faddr, ip->ip_src) || inp->inp_fport != uh->uh_sport) continue; } @@ -223,17 +273,41 @@ udp_input(m, va_alist) if (last != NULL) { struct mbuf *n; +#ifdef IPSEC + /* check AH/ESP integrity. */ + if (last != NULL && ipsec4_in_reject(m, last)) { + ipsecstat.in_polvio++; + /* do not inject data to pcb */ + } else +#endif /*IPSEC*/ if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { - if (sbappendaddr(&last->so_rcv, - sintosa(&udp_in), n, - (struct mbuf *)0) == 0) { + m_adj(m, iphlen); + if (last->inp_flags & INP_CONTROLOPTS + || last->inp_socket->so_options & + SO_TIMESTAMP) { + ip_savecontrol(last, &opts, + ip, n); + } + sa = (struct sockaddr *)&udpsrc; +#ifdef MAPPED_ADDR_ENABLED + if (last->inp_socket->so_proto->pr_domain->dom_family == AF_INET6) { + in6_sin_2_v4mapsin6(&udpsrc, + &mapped); + sa = (struct sockaddr *)&mapped; + } +#endif /* MAPPED_ADDR_ENABLED */ + if (sbappendaddr( + &last->inp_socket->so_rcv, + sa, n, opts) == 0) { m_freem(n); - udpstat.udps_fullsock++; + if (opts) + m_freem(opts); } else - sorwakeup(last); + sorwakeup(last->inp_socket); + opts = 0; } } - last = inp->inp_socket; + last = inp; /* * Don't look for additional matches if this one does * not have either the SO_REUSEPORT or SO_REUSEADDR @@ -242,7 +316,8 @@ udp_input(m, va_alist) * port. It * assumes that an application will never * clear these options after setting them. */ - if ((last->so_options&(SO_REUSEPORT|SO_REUSEADDR)) == 0) + if ((last->inp_socket->so_options & + (SO_REUSEPORT|SO_REUSEADDR)) == 0) break; } @@ -252,26 +327,43 @@ udp_input(m, va_alist) * (No need to send an ICMP Port Unreachable * for a broadcast or multicast datgram.) */ + udpstat.udps_noport++; udpstat.udps_noportbcast++; goto bad; } - if (sbappendaddr(&last->so_rcv, sintosa(&udp_in), m, - (struct mbuf *)0) == 0) { +#ifdef IPSEC + /* check AH/ESP integrity. */ + if (last != NULL && ipsec4_in_reject(m, last)) { + ipsecstat.in_polvio++; + goto bad; + } +#endif /*IPSEC*/ + if (last->inp_flags & INP_CONTROLOPTS || + last->inp_socket->so_options & SO_TIMESTAMP) + ip_savecontrol(last, &opts, ip, m); + sa = (struct sockaddr *)&udpsrc; +#ifdef MAPPED_ADDR_ENABLED + if (last->inp_socket->so_proto->pr_domain->dom_family == + AF_INET6) { + in6_sin_2_v4mapsin6(&udpsrc, &mapped); + sa = (struct sockaddr *)&mapped; + } +#endif /* MAPPED_ADDR_ENABLED */ + if (sbappendaddr(&last->inp_socket->so_rcv, sa, m, opts) == 0) { udpstat.udps_fullsock++; goto bad; } - sorwakeup(last); + sorwakeup(last->inp_socket); return; } /* * Locate pcb for datagram. */ - inp = in_pcbhashlookup(&udbtable, ip->ip_src, uh->uh_sport, + inp = in_pcblookup_connect(&udbtable, ip->ip_src, uh->uh_sport, ip->ip_dst, uh->uh_dport); if (inp == 0) { ++udpstat.udps_pcbhashmiss; - inp = in_pcblookup(&udbtable, ip->ip_src, uh->uh_sport, - ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD); + inp = in_pcblookup_bind(&udbtable, ip->ip_dst, uh->uh_dport); if (inp == 0) { udpstat.udps_noport++; if (m->m_flags & (M_BCAST | M_MCAST)) { @@ -279,50 +371,45 @@ udp_input(m, va_alist) goto bad; } *ip = save_ip; - ip->ip_len += iphlen; +#if NIPKDB > 0 + if (checkipkdb(&ip->ip_src, + uh->uh_sport, + uh->uh_dport, + m, + iphlen + sizeof(struct udphdr), + len - sizeof(struct udphdr))) + /* It was a debugger connect packet, just drop it now */ + goto bad; +#endif icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0); return; } } +#ifdef IPSEC + if (inp != NULL && ipsec4_in_reject(m, inp)) { + ipsecstat.in_polvio++; + goto bad; + } +#endif /*IPSEC*/ /* - * Construct sockaddr format source address. * Stuff source address and datagram in user buffer. */ - udp_in.sin_port = uh->uh_sport; - udp_in.sin_addr = ip->ip_src; - if (inp->inp_flags & INP_CONTROLOPTS) { - struct mbuf **mp = &opts; - - if (inp->inp_flags & INP_RECVDSTADDR) { - *mp = udp_saveopt((caddr_t) &ip->ip_dst, - sizeof(struct in_addr), IP_RECVDSTADDR); - if (*mp) - mp = &(*mp)->m_next; - } -#ifdef notyet - /* options were tossed above */ - if (inp->inp_flags & INP_RECVOPTS) { - *mp = udp_saveopt((caddr_t) opts_deleted_above, - sizeof(struct in_addr), IP_RECVOPTS); - if (*mp) - mp = &(*mp)->m_next; - } - /* ip_srcroute doesn't do what we want here, need to fix */ - if (inp->inp_flags & INP_RECVRETOPTS) { - *mp = udp_saveopt((caddr_t) ip_srcroute(), - sizeof(struct in_addr), IP_RECVRETOPTS); - if (*mp) - mp = &(*mp)->m_next; - } -#endif - } + if (inp->inp_flags & INP_CONTROLOPTS || + inp->inp_socket->so_options & SO_TIMESTAMP) + ip_savecontrol(inp, &opts, ip, m); iphlen += sizeof(struct udphdr); m->m_len -= iphlen; m->m_pkthdr.len -= iphlen; m->m_data += iphlen; - if (sbappendaddr(&inp->inp_socket->so_rcv, sintosa(&udp_in), m, - opts) == 0) { + sa = (struct sockaddr *)&udpsrc; +#ifdef MAPPED_ADDR_ENABLED + if (inp->inp_socket->so_proto->pr_domain->dom_family == AF_INET6) { + in6_sin_2_v4mapsin6(&udpsrc, &mapped); + sa = (struct sockaddr *)&mapped; + } +#endif /* MAPPED_ADDR_ENABLED */ + if (sbappendaddr(&inp->inp_socket->so_rcv, sa, m, opts) == 0) { udpstat.udps_fullsock++; goto bad; } @@ -332,31 +419,7 @@ bad: m_freem(m); if (opts) m_freem(opts); -} - -/* - * Create a "control" mbuf containing the specified data - * with the specified type for presentation with a datagram. - */ -struct mbuf * -udp_saveopt(p, size, type) - caddr_t p; - register int size; - int type; -{ - register struct cmsghdr *cp; - struct mbuf *m; - - if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL) - return ((struct mbuf *) NULL); - cp = (struct cmsghdr *) mtod(m, struct cmsghdr *); - bcopy(p, CMSG_DATA(cp), size); - size += sizeof(*cp); - m->m_len = size; - cp->cmsg_len = size; - cp->cmsg_level = IPPROTO_IP; - cp->cmsg_type = type; - return (m); + return; } /* @@ -368,6 +431,7 @@ udp_notify(inp, errno) register struct inpcb *inp; int errno; { + inp->inp_socket->so_error = errno; sorwakeup(inp->inp_socket); sowwakeup(inp->inp_socket); @@ -396,10 +460,11 @@ udp_ctlinput(cmd, sa, v) return NULL; if (ip) { uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2)); - in_pcbnotify(&udbtable, sa, uh->uh_dport, ip->ip_src, - uh->uh_sport, errno, notify); + in_pcbnotify(&udbtable, satosin(sa)->sin_addr, uh->uh_dport, + ip->ip_src, uh->uh_sport, errno, notify); } else - in_pcbnotifyall(&udbtable, sa, errno, notify); + in_pcbnotifyall(&udbtable, satosin(sa)->sin_addr, errno, + notify); return NULL; } @@ -433,6 +498,15 @@ udp_output(m, va_alist) } /* + * Compute the packet length of the IP header, and + * punt if the length looks bogus. + */ + if ((len + sizeof(struct udpiphdr)) > IP_MAXPACKET) { + error = EMSGSIZE; + goto release; + } + + /* * Fill in mbuf with extended UDP header * and addresses and length put into network format. */ @@ -458,6 +532,11 @@ udp_output(m, va_alist) ((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl; /* XXX */ ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; /* XXX */ udpstat.udps_opackets++; + +#ifdef IPSEC + m->m_pkthdr.rcvif = (struct ifnet *)inp->inp_socket; +#endif /*IPSEC*/ + return (ip_output(m, inp->inp_options, &inp->inp_route, inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST), inp->inp_moptions)); @@ -467,8 +546,8 @@ release: return (error); } -u_long udp_sendspace = 9216; /* really max datagram size */ -u_long udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in)); +int udp_sendspace = 9216; /* really max datagram size */ +int udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in)); /* 40 1K datagrams */ /*ARGSUSED*/ @@ -519,6 +598,10 @@ udp_usrreq(so, req, m, nam, control, p) break; inp = sotoinpcb(so); inp->inp_ip.ip_ttl = ip_defttl; +#ifdef IPSEC + inp = (struct inpcb *)so->so_pcb; + error = ipsec_init_policy(&inp->inp_sp); +#endif /*IPSEC*/ break; case PRU_DETACH: @@ -548,7 +631,8 @@ udp_usrreq(so, req, m, nam, control, p) /*soisdisconnected(so);*/ so->so_state &= ~SS_ISCONNECTED; /* XXX */ in_pcbdisconnect(inp); - inp->inp_laddr.s_addr = INADDR_ANY; /* XXX */ + inp->inp_laddr = zeroin_addr; /* XXX */ + in_pcbstate(inp, INP_BOUND); /* XXX */ break; case PRU_SHUTDOWN: @@ -567,10 +651,10 @@ udp_usrreq(so, req, m, nam, control, p) break; } { - struct in_addr laddr; + struct in_addr laddr; /* XXX */ if (nam) { - laddr = inp->inp_laddr; + laddr = inp->inp_laddr; /* XXX */ if ((so->so_state & SS_ISCONNECTED) != 0) { error = EISCONN; goto die; @@ -590,7 +674,8 @@ udp_usrreq(so, req, m, nam, control, p) error = udp_output(m, inp); if (nam) { in_pcbdisconnect(inp); - inp->inp_laddr = laddr; + inp->inp_laddr = laddr; /* XXX */ + in_pcbstate(inp, INP_BOUND); /* XXX */ } } break; @@ -648,6 +733,12 @@ udp_sysctl(name, namelen, oldp, oldlenp, switch (name[0]) { case UDPCTL_CHECKSUM: return (sysctl_int(oldp, oldlenp, newp, newlen, &udpcksum)); + case UDPCTL_SENDSPACE: + return (sysctl_int(oldp, oldlenp, newp, newlen, + &udp_sendspace)); + case UDPCTL_RECVSPACE: + return (sysctl_int(oldp, oldlenp, newp, newlen, + &udp_recvspace)); default: return (ENOPROTOOPT); }