summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormichele <michele@openbsd.org>2009-11-05 20:50:14 +0000
committermichele <michele@openbsd.org>2009-11-05 20:50:14 +0000
commitaf7905a8ccf622839e43d296d041c784fbb18090 (patch)
treec5173176b974d10978bf8c5075f2648a68521983
parentImplement -r option that dunps the contents of a PCI ROM to file. (diff)
downloadwireguard-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.c50
-rw-r--r--sys/conf/files3
-rw-r--r--sys/net/pf.c20
-rw-r--r--sys/netinet6/in6.h47
-rw-r--r--sys/netinet6/in6_proto.c18
-rw-r--r--sys/netinet6/ip6_divert.c339
-rw-r--r--sys/netinet6/ip6_divert.h65
-rw-r--r--usr.bin/netstat/inet.c8
-rw-r--r--usr.bin/netstat/inet6.c34
-rw-r--r--usr.bin/netstat/main.c5
-rw-r--r--usr.bin/netstat/netstat.h3
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);