diff options
author | 2009-11-05 20:50:14 +0000 | |
---|---|---|
committer | 2009-11-05 20:50:14 +0000 | |
commit | af7905a8ccf622839e43d296d041c784fbb18090 (patch) | |
tree | c5173176b974d10978bf8c5075f2648a68521983 | |
parent | Implement -r option that dunps the contents of a PCI ROM to file. (diff) | |
download | wireguard-openbsd-af7905a8ccf622839e43d296d041c784fbb18090.tar.xz wireguard-openbsd-af7905a8ccf622839e43d296d041c784fbb18090.zip |
IPv6 support for divert sockets.
tested by phessler@ pyr@
ok claudio@
"go ahead" deraadt@
-rw-r--r-- | sbin/sysctl/sysctl.c | 50 | ||||
-rw-r--r-- | sys/conf/files | 3 | ||||
-rw-r--r-- | sys/net/pf.c | 20 | ||||
-rw-r--r-- | sys/netinet6/in6.h | 47 | ||||
-rw-r--r-- | sys/netinet6/in6_proto.c | 18 | ||||
-rw-r--r-- | sys/netinet6/ip6_divert.c | 339 | ||||
-rw-r--r-- | sys/netinet6/ip6_divert.h | 65 | ||||
-rw-r--r-- | usr.bin/netstat/inet.c | 8 | ||||
-rw-r--r-- | usr.bin/netstat/inet6.c | 34 | ||||
-rw-r--r-- | usr.bin/netstat/main.c | 5 | ||||
-rw-r--r-- | usr.bin/netstat/netstat.h | 3 |
11 files changed, 576 insertions, 16 deletions
diff --git a/sbin/sysctl/sysctl.c b/sbin/sysctl/sysctl.c index 67ac1904ef7..cb982fbe583 100644 --- a/sbin/sysctl/sysctl.c +++ b/sbin/sysctl/sysctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sysctl.c,v 1.166 2009/10/27 23:59:34 deraadt Exp $ */ +/* $OpenBSD: sysctl.c,v 1.167 2009/11/05 20:50:14 michele Exp $ */ /* $NetBSD: sysctl.c,v 1.9 1995/09/30 07:12:50 thorpej Exp $ */ /* @@ -78,6 +78,7 @@ #include <netinet/icmp6.h> #include <netinet6/ip6_var.h> #include <netinet6/pim6_var.h> +#include <netinet6/ip6_divert.h> #endif #include <netmpls/mpls.h> @@ -562,7 +563,8 @@ parse(char *string, int flags) if (len < 0) return; - if ((mib[2] == IPPROTO_PIM && mib[3] == PIM6CTL_STATS)) { + if ((mib[2] == IPPROTO_PIM && mib[3] == PIM6CTL_STATS) || + (mib[2] == IPPROTO_DIVERT && mib[3] == DIVERT6CTL_STATS)) { if (flags == 0) return; warnx("use netstat to view %s information", @@ -1966,6 +1968,7 @@ struct ctlname inet6name[] = CTL_IPV6PROTO_NAMES; struct ctlname ip6name[] = IPV6CTL_NAMES; struct ctlname icmp6name[] = ICMPV6CTL_NAMES; struct ctlname pim6name[] = PIM6CTL_NAMES; +struct ctlname divert6name[] = DIVERT6CTL_NAMES; struct list inet6list = { inet6name, IPV6PROTO_MAXID }; struct list inet6vars[] = { /*0*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, @@ -2004,6 +2007,49 @@ struct list inet6vars[] = { { 0, 0 }, { 0, 0 }, { pim6name, PIM6CTL_MAXID }, /* pim6 */ + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, +/*110*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, +/*120*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, +/*130*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, +/*140*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, +/*150*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, +/*160*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, +/*170*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, +/*180*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, +/*190*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, +/*200*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, +/*210*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, +/*220*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, +/*230*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, +/*240*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, +/*250*/ { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { divert6name, DIVERT6CTL_MAXID }, }; /* diff --git a/sys/conf/files b/sys/conf/files index 336ca660de3..d2fe3fbd3b4 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,4 +1,4 @@ -# $OpenBSD: files,v 1.479 2009/10/08 20:35:44 matthieu Exp $ +# $OpenBSD: files,v 1.480 2009/11/05 20:50:14 michele Exp $ # $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $ # @(#)files.newconf 7.5 (Berkeley) 5/10/93 @@ -1009,6 +1009,7 @@ file netinet/in_gif.c gif & inet file netinet6/in6_gif.c gif & inet6 file netinet6/in6_pcb.c inet6 file netinet6/in6.c inet6 +file netinet6/ip6_divert.c inet6 & pf file netinet6/in6_ifattach.c inet6 file netinet6/in6_cksum.c inet6 file netinet6/in6_src.c inet6 diff --git a/sys/net/pf.c b/sys/net/pf.c index 0d0163c9110..d5537cc5aaf 100644 --- a/sys/net/pf.c +++ b/sys/net/pf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf.c,v 1.667 2009/11/03 10:59:04 claudio Exp $ */ +/* $OpenBSD: pf.c,v 1.668 2009/11/05 20:50:14 michele Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -91,6 +91,7 @@ #include <netinet/in_pcb.h> #include <netinet/icmp6.h> #include <netinet6/nd6.h> +#include <netinet6/ip6_divert.h> #endif /* INET6 */ @@ -5830,6 +5831,9 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, if (m->m_pkthdr.pf.flags & PF_TAG_GENERATED) return (PF_PASS); + if (m->m_pkthdr.pf.flags & PF_TAG_DIVERTED_PACKET) + return (PF_PASS); + /* packet reassembly */ if (pf_normalize_ip6(m0, dir, kif, &reason, &pd) != PF_PASS) { action = PF_DROP; @@ -6129,6 +6133,15 @@ done: } } + if (action == PF_PASS && r->divert_packet.port) { + struct pf_divert *divert; + + if ((divert = pf_get_divert(m))) + divert->port = r->divert_packet.port; + + action = PF_DIVERT; + } + if (log) { struct pf_rule *lr; @@ -6194,6 +6207,11 @@ done: *m0 = NULL; action = PF_PASS; break; + case PF_DIVERT: + divert6_packet(m, dir); + *m0 = NULL; + action = PF_PASS; + break; default: /* pf_route6 can free the mbuf causing *m0 to become NULL */ if (r->rt) diff --git a/sys/netinet6/in6.h b/sys/netinet6/in6.h index 7cab2a6b4a0..c50b86e0547 100644 --- a/sys/netinet6/in6.h +++ b/sys/netinet6/in6.h @@ -1,4 +1,4 @@ -/* $OpenBSD: in6.h,v 1.47 2008/11/25 12:11:44 markus Exp $ */ +/* $OpenBSD: in6.h,v 1.48 2009/11/05 20:50:14 michele Exp $ */ /* $KAME: in6.h,v 1.83 2001/03/29 02:55:07 jinmei Exp $ */ /* @@ -529,7 +529,7 @@ struct ip6_mtuinfo { * Third level is protocol number. * Fourth level is desired variable within that protocol. */ -#define IPV6PROTO_MAXID (IPPROTO_PIM + 1) /* don't list to IPV6PROTO_MAX */ +#define IPV6PROTO_MAXID (IPPROTO_DIVERT + 1) /* don't list to IPV6PROTO_MAX */ #define CTL_IPV6PROTO_NAMES { \ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ @@ -576,6 +576,49 @@ struct ip6_mtuinfo { { 0, 0 }, \ { 0, 0 }, \ { "pim6", CTLTYPE_NODE }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { 0, 0 }, \ +/*110*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ +/*120*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ +/*130*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ +/*140*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ +/*150*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ +/*160*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ +/*170*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ +/*180*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ +/*190*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ +/*200*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ +/*210*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ +/*220*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ +/*230*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ +/*240*/ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \ +/*250*/ { 0, 0 }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { 0, 0 }, \ + { "divert", CTLTYPE_NODE }, \ } /* diff --git a/sys/netinet6/in6_proto.c b/sys/netinet6/in6_proto.c index 52aa3df8fb9..c575bae7279 100644 --- a/sys/netinet6/in6_proto.c +++ b/sys/netinet6/in6_proto.c @@ -1,4 +1,4 @@ -/* $OpenBSD: in6_proto.c,v 1.57 2008/11/25 12:11:45 markus Exp $ */ +/* $OpenBSD: in6_proto.c,v 1.58 2009/11/05 20:50:14 michele Exp $ */ /* $KAME: in6_proto.c,v 1.66 2000/10/10 15:35:47 itojun Exp $ */ /* @@ -113,6 +113,11 @@ #include <netinet/ip_carp.h> #endif +#include "pf.h" +#if NPF > 0 +#include <netinet6/ip6_divert.h> +#endif + /* * TCP/IP protocol family: IP6, ICMP6, UDP, TCP. */ @@ -224,15 +229,22 @@ struct ip6protosw inet6sw[] = { #endif #if NCARP > 0 { SOCK_RAW, &inet6domain, IPPROTO_CARP, PR_ATOMIC|PR_ADDR, - carp6_proto_input, rip6_output, 0, rip6_ctloutput, + carp6_proto_input, rip6_output, 0, rip6_ctloutput, rip6_usrreq, 0, 0, 0, 0, carp_sysctl }, #endif /* NCARP */ +#if NPF > 0 +{ SOCK_RAW, &inet6domain, IPPROTO_DIVERT, PR_ATOMIC|PR_ADDR, + divert6_input, 0, 0, rip6_ctloutput, + divert6_usrreq, + divert6_init, 0, 0, 0, divert6_sysctl +}, +#endif /* NPF > 0 */ /* raw wildcard */ { SOCK_RAW, &inet6domain, 0, PR_ATOMIC|PR_ADDR, rip6_input, rip6_output, 0, rip6_ctloutput, - rip6_usrreq, rip6_init, + rip6_usrreq, rip6_init, 0, 0, 0, }, }; diff --git a/sys/netinet6/ip6_divert.c b/sys/netinet6/ip6_divert.c new file mode 100644 index 00000000000..e39dfc757c7 --- /dev/null +++ b/sys/netinet6/ip6_divert.c @@ -0,0 +1,339 @@ +/* $OpenBSD: ip6_divert.c,v 1.1 2009/11/05 20:50:14 michele Exp $ */ + +/* + * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/sysctl.h> + +#include <net/if.h> +#include <net/route.h> +#include <net/netisr.h> +#include <net/pfvar.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/in_pcb.h> +#include <netinet/ip6.h> +#include <netinet6/in6_var.h> +#include <netinet6/in6_var.h> +#include <netinet6/ip6_divert.h> + +struct inpcbtable divb6table; +struct div6stat div6stat; + +#ifndef DIVERT_SENDSPACE +#define DIVERT_SENDSPACE (65536 + 100) +#endif +u_int divert6_sendspace = DIVERT_SENDSPACE; +#ifndef DIVERT_RECVSPACE +#define DIVERT_RECVSPACE (65536 + 100) +#endif +u_int divert6_recvspace = DIVERT_RECVSPACE; + +#ifndef DIVERTHASHSIZE +#define DIVERTHASHSIZE 128 +#endif + +int *divert6ctl_vars[DIVERT6CTL_MAXID] = DIVERT6CTL_VARS; + +int divb6hashsize = DIVERTHASHSIZE; + +void divert6_detach(struct inpcb *); + +void +divert6_init() +{ + in_pcbinit(&divb6table, divb6hashsize); +} + +int +divert6_input(struct mbuf **mp, int *offp, int proto) +{ + m_freem(*mp); + + return (0); +} + +int +divert6_output(struct mbuf *m, ...) +{ + struct inpcb *inp; + struct ifqueue *inq; + struct mbuf *nam, *control; + struct sockaddr_in6 *sin6; + struct socket *so; + struct ifaddr *ifa; + int s, error = 0; + va_list ap; + + va_start(ap, m); + inp = va_arg(ap, struct inpcb *); + nam = va_arg(ap, struct mbuf *); + control = va_arg(ap, struct mbuf *); + va_end(ap); + + m->m_pkthdr.rcvif = NULL; + m->m_nextpkt = NULL; + m->m_pkthdr.rdomain = inp->inp_rdomain; + + if (control) + m_freem(control); + + sin6 = mtod(nam, struct sockaddr_in6 *); + so = inp->inp_socket; + + m->m_pkthdr.pf.flags |= PF_TAG_DIVERTED_PACKET; + + if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { + ifa = ifa_ifwithaddr((struct sockaddr *)sin6, 0); + if (ifa == NULL) { + div6stat.divs_errors++; + m_freem(m); + return (EADDRNOTAVAIL); + } + m->m_pkthdr.rcvif = ifa->ifa_ifp; + + inq = &ip6intrq; + + s = splnet(); + IF_INPUT_ENQUEUE(inq, m); + schednetisr(NETISR_IPV6); + splx(s); + } else { + error = ip6_output(m, NULL, &inp->inp_route6, + ((so->so_options & SO_DONTROUTE) ? IP_ROUTETOIF : 0) + | IP_ALLOWBROADCAST | IP_RAWOUTPUT, NULL, NULL, NULL); + } + + div6stat.divs_opackets++; + return (error); +} + +void +divert6_packet(struct mbuf *m, int dir) +{ + struct inpcb *inp; + struct socket *sa = NULL; + struct sockaddr_in6 addr; + struct pf_divert *pd; + + div6stat.divs_ipackets++; + + if (m->m_len < sizeof(struct ip6_hdr) && + (m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) { + div6stat.divs_errors++; + return; + } + + pd = pf_find_divert(m); + if (pd == NULL) { + div6stat.divs_errors++; + m_freem(m); + return; + } + + bzero(&addr, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_len = sizeof(addr); + + if (dir == PF_IN) { + struct ifaddr *ifa; + struct ifnet *ifp; + + ifp = m->m_pkthdr.rcvif; + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + addr.sin6_addr = ((struct sockaddr_in6 *) + ifa->ifa_addr)->sin6_addr; + break; + } + } + + CIRCLEQ_FOREACH(inp, &divb6table.inpt_queue, inp_queue) { + if (inp->inp_lport != pd->port) + continue; + + sa = inp->inp_socket; + if (sbappendaddr(&sa->so_rcv, (struct sockaddr *)&addr, + m, NULL) == 0) { + div6stat.divs_fullsock++; + m_freem(m); + return; + } else + sorwakeup(inp->inp_socket); + break; + } + + if (sa == NULL) { + div6stat.divs_noport++; + m_freem(m); + } +} + +/*ARGSUSED*/ +int +divert6_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *addr, + struct mbuf *control, struct proc *p) +{ + struct inpcb *inp = sotoinpcb(so); + int error = 0; + int s; + + if (req == PRU_CONTROL) { + return (in6_control(so, (u_long)m, (caddr_t)addr, + (struct ifnet *)control, p)); + } + if (inp == NULL && req != PRU_ATTACH) { + error = EINVAL; + goto release; + } + switch (req) { + + case PRU_ATTACH: + if (inp != NULL) { + error = EINVAL; + break; + } + if ((so->so_state & SS_PRIV) == 0) { + error = EACCES; + break; + } + s = splsoftnet(); + error = in_pcballoc(so, &divb6table); + splx(s); + if (error) + break; + + error = soreserve(so, divert6_sendspace, divert6_recvspace); + if (error) + break; + ((struct inpcb *) so->so_pcb)->inp_flags |= INP_HDRINCL; + break; + + case PRU_DETACH: + divert6_detach(inp); + break; + + case PRU_BIND: + s = splsoftnet(); + error = in6_pcbbind(inp, addr, p); + splx(s); + break; + + case PRU_SHUTDOWN: + socantsendmore(so); + break; + + case PRU_SEND: + return (divert6_output(m, inp, addr, control)); + + case PRU_ABORT: + soisdisconnected(so); + divert6_detach(inp); + break; + + case PRU_SOCKADDR: + in6_setsockaddr(inp, addr); + break; + + case PRU_PEERADDR: + in6_setpeeraddr(inp, addr); + break; + + case PRU_SENSE: + return (0); + + case PRU_LISTEN: + case PRU_CONNECT: + case PRU_CONNECT2: + case PRU_ACCEPT: + case PRU_DISCONNECT: + case PRU_SENDOOB: + case PRU_FASTTIMO: + case PRU_SLOWTIMO: + case PRU_PROTORCV: + case PRU_PROTOSEND: + error = EOPNOTSUPP; + break; + + case PRU_RCVD: + case PRU_RCVOOB: + return (EOPNOTSUPP); /* do not free mbuf's */ + + default: + panic("divert6_usrreq"); + } + +release: + if (control) { + m_freem(control); + } + if (m) + m_freem(m); + return (error); +} + +void +divert6_detach(struct inpcb *inp) +{ + int s = splsoftnet(); + + in_pcbdetach(inp); + splx(s); +} + +/* + * Sysctl for divert variables. + */ +int +divert6_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, + void *newp, size_t newlen) +{ + /* All sysctl names at this level are terminal. */ + if (namelen != 1) + return (ENOTDIR); + + switch (name[0]) { + case DIVERT6CTL_SENDSPACE: + return (sysctl_int(oldp, oldlenp, newp, newlen, + &divert6_sendspace)); + case DIVERT6CTL_RECVSPACE: + return (sysctl_int(oldp, oldlenp, newp, newlen, + &divert6_recvspace)); + case DIVERT6CTL_STATS: + if (newp != NULL) + return (EPERM); + return (sysctl_struct(oldp, oldlenp, newp, newlen, + &div6stat, sizeof(div6stat))); + default: + if (name[0] < DIVERT6CTL_MAXID) + return sysctl_int_arr(divert6ctl_vars, name, namelen, + oldp, oldlenp, newp, newlen); + + return (ENOPROTOOPT); + } + /* NOTREACHED */ +} diff --git a/sys/netinet6/ip6_divert.h b/sys/netinet6/ip6_divert.h new file mode 100644 index 00000000000..47d18320e99 --- /dev/null +++ b/sys/netinet6/ip6_divert.h @@ -0,0 +1,65 @@ +/* $OpenBSD: ip6_divert.h,v 1.1 2009/11/05 20:50:14 michele Exp $ */ + +/* + * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _IP6_DIVERT_H_ +#define _IP6_DIVERT_H_ + +struct div6stat { + u_long divs_ipackets; /* total input packets */ + u_long divs_noport; /* no socket on port */ + u_long divs_fullsock; /* not delivered, input socket full */ + u_long divs_opackets; /* total output packets */ + u_long divs_errors; /* generic errors */ +}; + +/* + * Names for divert sysctl objects + */ +#define DIVERT6CTL_RECVSPACE 1 /* receive buffer space */ +#define DIVERT6CTL_SENDSPACE 2 /* send buffer space */ +#define DIVERT6CTL_STATS 3 /* divert statistics */ +#define DIVERT6CTL_MAXID 4 + +#define DIVERT6CTL_NAMES { \ + { 0, 0 }, \ + { "recvspace", CTLTYPE_INT }, \ + { "sendspace", CTLTYPE_INT }, \ + { "stats", CTLTYPE_STRUCT } \ +} + +#define DIVERT6CTL_VARS { \ + NULL, \ + &divert6_recvspace, \ + &divert6_sendspace, \ + NULL \ +} + +#ifdef _KERNEL +extern struct inpcbtable divb6table; +extern struct div6stat div6stat; + +void divert6_init(void); +int divert6_input(struct mbuf **, int *, int); +void divert6_packet(struct mbuf *, int); +int divert6_output(struct mbuf *, ...); +int divert6_sysctl(int *, u_int, void *, size_t *, void *, size_t); +int divert6_usrreq(struct socket *, + int, struct mbuf *, struct mbuf *, struct mbuf *, struct proc *); + +#endif /* _KERNEL */ +#endif /* _IP6_DIVERT_H_ */ diff --git a/usr.bin/netstat/inet.c b/usr.bin/netstat/inet.c index 873a1a2074e..c5ff5257aca 100644 --- a/usr.bin/netstat/inet.c +++ b/usr.bin/netstat/inet.c @@ -1,4 +1,4 @@ -/* $OpenBSD: inet.c,v 1.111 2009/10/04 16:08:37 michele Exp $ */ +/* $OpenBSD: inet.c,v 1.112 2009/11/05 20:50:14 michele Exp $ */ /* $NetBSD: inet.c,v 1.14 1995/10/03 21:42:37 thorpej Exp $ */ /* @@ -174,12 +174,12 @@ protopr0(u_long off, char *name, int af) printf(" (including servers)"); putchar('\n'); if (Aflag) - printf("%-*.*s %-6.6s %-6.6s %-6.6s %-18.18s %-18.18s %s\n", + printf("%-*.*s %-7.7s %-6.6s %-6.6s %-18.18s %-18.18s %s\n", PLEN, PLEN, "PCB", "Proto", "Recv-Q", "Send-Q", "Local Address", "Foreign Address", "(state)"); else - printf("%-6.6s %-6.6s %-6.6s %-22.22s %-22.22s %s\n", + printf("%-7.7s %-6.6s %-6.6s %-22.22s %-22.22s %s\n", "Proto", "Recv-Q", "Send-Q", "Local Address", "Foreign Address", "(state)"); @@ -197,7 +197,7 @@ protopr0(u_long off, char *name, int af) name = namebuf; } else name = name0; - printf("%-6.6s %6ld %6ld ", name, sockb.so_rcv.sb_cc, + printf("%-7.7s %6ld %6ld ", name, sockb.so_rcv.sb_cc, sockb.so_snd.sb_cc); if (inpcb.inp_flags & INP_IPV6) { inet6print(&inpcb.inp_laddr6, (int)inpcb.inp_lport, diff --git a/usr.bin/netstat/inet6.c b/usr.bin/netstat/inet6.c index 4889b138670..56c173e2e69 100644 --- a/usr.bin/netstat/inet6.c +++ b/usr.bin/netstat/inet6.c @@ -1,4 +1,4 @@ -/* $OpenBSD: inet6.c,v 1.39 2009/07/17 14:21:37 tedu Exp $ */ +/* $OpenBSD: inet6.c,v 1.40 2009/11/05 20:50:14 michele Exp $ */ /* BSDI inet.c,v 2.3 1995/10/24 02:19:29 prb Exp */ /* * Copyright (c) 1983, 1988, 1993 @@ -51,6 +51,7 @@ #include <netinet6/in6_var.h> #include <netinet6/pim6_var.h> #include <netinet6/raw_ip6.h> +#include <netinet6/ip6_divert.h> #include <arpa/inet.h> #if 0 @@ -1031,6 +1032,37 @@ rip6_stats(char *name) } /* + * Dump divert6 statistics structure. + */ +void +div6_stats(char *name) +{ + struct div6stat div6stat; + int mib[] = { CTL_NET, AF_INET6, IPPROTO_DIVERT, DIVERT6CTL_STATS }; + size_t len = sizeof(div6stat); + + if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), + &div6stat, &len, NULL, 0) == -1) { + if (errno != ENOPROTOOPT) + warn(name); + return; + } + + printf("%s:\n", name); +#define p(f, m) if (div6stat.f || sflag <= 1) \ + printf(m, div6stat.f, plural(div6stat.f)) +#define p1(f, m) if (div6stat.f || sflag <= 1) \ + printf(m, div6stat.f) + p(divs_ipackets, "\t%lu total packet%s received\n"); + p1(divs_noport, "\t%lu dropped due to no socket\n"); + p1(divs_fullsock, "\t%lu dropped due to full socket buffers\n"); + p(divs_opackets, "\t%lu packet%s output\n"); + p1(divs_errors, "\t%lu errors\n"); +#undef p +#undef p1 +} + +/* * Pretty print an Internet address (net address + port). * If the nflag was specified, use numbers instead of names. */ diff --git a/usr.bin/netstat/main.c b/usr.bin/netstat/main.c index 4fe7e9c64c6..ba2c79b4528 100644 --- a/usr.bin/netstat/main.c +++ b/usr.bin/netstat/main.c @@ -1,4 +1,4 @@ -/* $OpenBSD: main.c,v 1.80 2009/10/04 16:08:37 michele Exp $ */ +/* $OpenBSD: main.c,v 1.81 2009/11/05 20:50:14 michele Exp $ */ /* $NetBSD: main.c,v 1.9 1996/05/07 02:55:02 thorpej Exp $ */ /* @@ -89,6 +89,8 @@ struct nlist nl[] = { { "_rawin6pcbtable" }, #define N_DIVBTABLE 15 { "_divbtable" }, +#define N_DIVB6TABLE 16 + { "_divb6table" }, { ""} }; @@ -122,6 +124,7 @@ struct protox ip6protox[] = { { N_TCBTABLE, ip6protopr, NULL, tcp_dump, "tcp" }, { N_UDBTABLE, ip6protopr, NULL, NULL, "udp" }, { N_RAWIP6TABLE,ip6protopr, ip6_stats, NULL, "ip6" }, + { N_DIVB6TABLE, ip6protopr, div6_stats, NULL, "divert6" }, { -1, NULL, icmp6_stats, NULL, "icmp6" }, { -1, NULL, pim6_stats, NULL, "pim6" }, { -1, NULL, rip6_stats, NULL, "rip6" }, diff --git a/usr.bin/netstat/netstat.h b/usr.bin/netstat/netstat.h index 6e23a1e3cb5..87a4c8f4c0a 100644 --- a/usr.bin/netstat/netstat.h +++ b/usr.bin/netstat/netstat.h @@ -1,4 +1,4 @@ -/* $OpenBSD: netstat.h,v 1.51 2009/10/04 16:08:37 michele Exp $ */ +/* $OpenBSD: netstat.h,v 1.52 2009/11/05 20:50:14 michele Exp $ */ /* $NetBSD: netstat.h,v 1.6 1996/05/07 02:55:05 thorpej Exp $ */ /* @@ -111,6 +111,7 @@ void ip6_ifstats(char *); void icmp6_stats(char *); void icmp6_ifstats(char *); void pim6_stats(char *); +void div6_stats(char *); void rip6_stats(char *); void mroute6pr(u_long, u_long); void mrt6_stats(void); |