📄 udp6_usrreq.c
字号:
//==========================================================================
//
// src/sys/netinet6/udp6_usrreq.c
//
//==========================================================================
//####BSDCOPYRIGHTBEGIN####
//
// -------------------------------------------
//
// Portions of this software may have been derived from OpenBSD,
// FreeBSD or other sources, and are covered by the appropriate
// copyright disclaimers included herein.
//
// Portions created by Red Hat are
// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
//
// -------------------------------------------
//
//####BSDCOPYRIGHTEND####
//==========================================================================
/* $FreeBSD: src/sys/netinet6/udp6_usrreq.c,v 1.6.2.6 2001/07/29 19:32:40 ume Exp $ */
/* $KAME: udp6_usrreq.c,v 1.43 2001/11/12 05:04:16 jinmei Exp $ */
/*
* 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, 1989, 1993
* The Regents of the University of California. 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
*
* @(#)udp_var.h 8.1 (Berkeley) 6/10/93
*/
#include <sys/param.h>
#include <sys/mbuf.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/sysctl.h>
#include <sys/errno.h>
#include <net/if.h>
#include <net/route.h>
#include <net/if_types.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/in_pcb.h>
#include <netinet/in_var.h>
#include <netinet/ip_var.h>
#include <netinet/udp.h>
#include <netinet/udp_var.h>
#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
#include <netinet6/in6_pcb.h>
#include <netinet/icmp6.h>
#include <netinet6/udp6_var.h>
#include <netinet6/ip6protosw.h>
#ifdef IPSEC
#include <netinet6/ipsec.h>
#endif /* IPSEC */
/*
* UDP protocol inplementation.
* Per RFC 768, August, 1980.
*/
extern struct protosw inetsw[];
static int udp6_detach __P((struct socket *so));
int
udp6_input(mp, offp, proto)
struct mbuf **mp;
int *offp, proto;
{
struct mbuf *m = *mp;
register struct ip6_hdr *ip6;
register struct udphdr *uh;
register struct inpcb *in6p;
struct ip6_recvpktopts opts;
int off = *offp;
int plen, ulen;
struct sockaddr_in6 udp_in6;
bzero(&opts, sizeof(opts));
ip6 = mtod(m, struct ip6_hdr *);
#if defined(NFAITH) && 0 < NFAITH
if (faithprefix(&ip6->ip6_dst)) {
/* XXX send icmp6 host/port unreach? */
m_freem(m);
return IPPROTO_DONE;
}
#endif
#ifndef PULLDOWN_TEST
IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE);
ip6 = mtod(m, struct ip6_hdr *);
uh = (struct udphdr *)((caddr_t)ip6 + off);
#else
IP6_EXTHDR_GET(uh, struct udphdr *, m, off, sizeof(*uh));
if (!uh)
return IPPROTO_DONE;
#endif
udpstat.udps_ipackets++;
plen = ntohs(ip6->ip6_plen) - off + sizeof(*ip6);
ulen = ntohs((u_short)uh->uh_ulen);
if (plen != ulen) {
udpstat.udps_badlen++;
goto bad;
}
/*
* Checksum extended UDP header and data.
*/
if (uh->uh_sum == 0)
udpstat.udps_nosum++;
else if (in6_cksum(m, IPPROTO_UDP, off, ulen) != 0) {
udpstat.udps_badsum++;
goto bad;
}
if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
struct inpcb *last;
/*
* Deliver a multicast datagram to all sockets
* for which the local and remote addresses and ports match
* those of the incoming datagram. This allows more than
* one process to receive multicasts on the same port.
* (This really ought to be done for unicast datagrams as
* well, but that would cause problems with existing
* applications that open both address-specific sockets and
* a wildcard socket listening to the same port -- they would
* end up receiving duplicates of every unicast datagram.
* Those applications open the multiple sockets to overcome an
* inadequacy of the UDP socket interface, but for backwards
* compatibility we avoid the problem here rather than
* fixing the interface. Maybe 4.5BSD will remedy this?)
*/
/*
* In a case that laddr should be set to the link-local
* address (this happens in RIPng), the multicast address
* specified in the received packet does not match with
* laddr. To cure this situation, the matching is relaxed
* if the receiving interface is the same as one specified
* in the socket and if the destination multicast address
* matches one of the multicast groups specified in the socket.
*/
/*
* Construct sockaddr format source address.
*/
init_sin6(&udp_in6, m); /* general init */
udp_in6.sin6_port = uh->uh_sport;
/*
* KAME note: traditionally we dropped udpiphdr from mbuf here.
* We need udphdr for IPsec processing so we do that later.
*/
/*
* Locate pcb(s) for datagram.
* (Algorithm copied from raw_intr().)
*/
last = NULL;
LIST_FOREACH(in6p, &udb, inp_list) {
if ((in6p->inp_vflag & INP_IPV6) == 0)
continue;
if (in6p->in6p_lport != uh->uh_dport)
continue;
if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) {
if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr,
&ip6->ip6_dst))
continue;
}
if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr,
&ip6->ip6_src) ||
in6p->in6p_fport != uh->uh_sport)
continue;
}
if (last != NULL) {
struct mbuf *n;
#ifdef IPSEC
/*
* Check AH/ESP integrity.
*/
if (ipsec6_in_reject_so(m, last->inp_socket))
ipsec6stat.in_polvio++;
/* do not inject data into pcb */
else
#endif /* IPSEC */
if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
/*
* KAME NOTE: do not
* m_copy(m, offset, ...) above.
* sbappendaddr() expects M_PKTHDR,
* and m_copy() will copy M_PKTHDR
* only if offset is 0.
*/
if (last->in6p_flags & IN6P_CONTROLOPTS
|| last->in6p_socket->so_options & SO_TIMESTAMP)
ip6_savecontrol(last, ip6, n,
&opts, NULL);
m_adj(n, off + sizeof(struct udphdr));
if (sbappendaddr(&last->in6p_socket->so_rcv,
(struct sockaddr *)&udp_in6,
n, opts.head) == 0) {
m_freem(n);
if (opts.head)
m_freem(opts.head);
udpstat.udps_fullsock++;
} else
sorwakeup(last->in6p_socket);
bzero(&opts, sizeof(opts));
}
}
last = in6p;
/*
* Don't look for additional matches if this one does
* not have either the SO_REUSEPORT or SO_REUSEADDR
* socket options set. This heuristic avoids searching
* through all pcbs in the common case of a non-shared
* port. It assumes that an application will never
* clear these options after setting them.
*/
if ((last->in6p_socket->so_options &
(SO_REUSEPORT|SO_REUSEADDR)) == 0)
break;
}
if (last == NULL) {
/*
* No matching pcb found; discard datagram.
* (No need to send an ICMP Port Unreachable
* for a broadcast or multicast datgram.)
*/
udpstat.udps_noport++;
udpstat.udps_noportmcast++;
goto bad;
}
#ifdef IPSEC
/*
* Check AH/ESP integrity.
*/
if (ipsec6_in_reject_so(m, last->inp_socket)) {
ipsec6stat.in_polvio++;
goto bad;
}
#endif /* IPSEC */
if (last->in6p_flags & IN6P_CONTROLOPTS
|| last->in6p_socket->so_options & SO_TIMESTAMP)
ip6_savecontrol(last, ip6, m, &opts, NULL);
m_adj(m, off + sizeof(struct udphdr));
if (sbappendaddr(&last->in6p_socket->so_rcv,
(struct sockaddr *)&udp_in6,
m, opts.head) == 0) {
udpstat.udps_fullsock++;
goto bad;
}
sorwakeup(last->in6p_socket);
return IPPROTO_DONE;
}
/*
* Locate pcb for datagram.
*/
in6p = in6_pcblookup_hash(&udbinfo, &ip6->ip6_src, uh->uh_sport,
&ip6->ip6_dst, uh->uh_dport, 1,
m->m_pkthdr.rcvif);
if (in6p == 0) {
if (log_in_vain) {
char buf[INET6_ADDRSTRLEN];
strcpy(buf, ip6_sprintf(&ip6->ip6_dst));
log(LOG_INFO,
"Connection attempt to UDP %s:%d from %s:%d\n",
buf, ntohs(uh->uh_dport),
ip6_sprintf(&ip6->ip6_src), ntohs(uh->uh_sport));
}
udpstat.udps_noport++;
if (m->m_flags & M_MCAST) {
printf("UDP6: M_MCAST is set in a unicast packet.\n");
udpstat.udps_noportmcast++;
goto bad;
}
icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0);
return IPPROTO_DONE;
}
#ifdef IPSEC
/*
* Check AH/ESP integrity.
*/
if (ipsec6_in_reject_so(m, in6p->in6p_socket)) {
ipsec6stat.in_polvio++;
goto bad;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -