summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/net/pf.c9
-rw-r--r--sys/netinet/in.h6
-rw-r--r--sys/netinet/in_pcb.h3
-rw-r--r--sys/netinet/ip_divert.c30
-rw-r--r--sys/netinet/ip_divert.h4
-rw-r--r--sys/netinet/raw_ip.c38
-rw-r--r--sys/netinet6/ip6_divert.c30
-rw-r--r--sys/netinet6/ip6_divert.h4
-rw-r--r--sys/netinet6/raw_ip6.c39
9 files changed, 128 insertions, 35 deletions
diff --git a/sys/net/pf.c b/sys/net/pf.c
index 58742d22ae5..f8fd5774176 100644
--- a/sys/net/pf.c
+++ b/sys/net/pf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf.c,v 1.812 2012/09/19 12:35:07 blambert Exp $ */
+/* $OpenBSD: pf.c,v 1.813 2012/10/21 13:06:02 benno Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -6973,15 +6973,16 @@ done:
case PF_DIVERT:
switch (pd.af) {
case AF_INET:
- divert_packet(pd.m, pd.dir);
+ if (divert_packet(pd.m, pd.dir) == 0)
+ *m0 = NULL;
break;
#ifdef INET6
case AF_INET6:
- divert6_packet(pd.m, pd.dir);
+ if (divert6_packet(pd.m, pd.dir) == 0)
+ *m0 = NULL;
break;
#endif /* INET6 */
}
- *m0 = NULL;
action = PF_PASS;
break;
#if INET && INET6
diff --git a/sys/netinet/in.h b/sys/netinet/in.h
index e503188ddaf..1a9053768a0 100644
--- a/sys/netinet/in.h
+++ b/sys/netinet/in.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: in.h,v 1.94 2012/09/15 00:47:08 guenther Exp $ */
+/* $OpenBSD: in.h,v 1.95 2012/10/21 13:06:03 benno Exp $ */
/* $NetBSD: in.h,v 1.20 1996/02/13 23:41:47 christos Exp $ */
/*
@@ -306,7 +306,11 @@ struct ip_opts {
#define IP_IPSECFLOWINFO 36 /* bool; IPsec flow info for dgram */
#define IP_RTABLE 0x1021 /* int; routing table, see SO_RTABLE */
+#define IP_DIVERTFL 0x1022 /* int; divert direction flag opt */
+/* Values used by IP_DIVERTFL socket option */
+#define IPPROTO_DIVERT_RESP 0x01 /* divert response packets */
+#define IPPROTO_DIVERT_INIT 0x02 /* divert packets initial direction */
#if __BSD_VISIBLE
/*
diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h
index 0ec3cdc01ec..9357981d112 100644
--- a/sys/netinet/in_pcb.h
+++ b/sys/netinet/in_pcb.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: in_pcb.h,v 1.73 2012/09/17 20:01:26 yasuoka Exp $ */
+/* $OpenBSD: in_pcb.h,v 1.74 2012/10/21 13:06:03 benno Exp $ */
/* $NetBSD: in_pcb.h,v 1.14 1996/02/13 23:42:00 christos Exp $ */
/*
@@ -148,6 +148,7 @@ struct inpcb {
void *inp_pf_sk;
u_int inp_rtableid;
int inp_pipex; /* pipex indication */
+ int inp_divertfl; /* divert flags */
};
struct inpcbtable {
diff --git a/sys/netinet/ip_divert.c b/sys/netinet/ip_divert.c
index 9f0227a5ef5..1980d8e213a 100644
--- a/sys/netinet/ip_divert.c
+++ b/sys/netinet/ip_divert.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_divert.c,v 1.9 2012/07/13 16:27:30 claudio Exp $ */
+/* $OpenBSD: ip_divert.c,v 1.10 2012/10/21 13:06:03 benno Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -133,7 +133,7 @@ divert_output(struct mbuf *m, ...)
return (error);
}
-void
+int
divert_packet(struct mbuf *m, int dir)
{
struct inpcb *inp;
@@ -141,19 +141,32 @@ divert_packet(struct mbuf *m, int dir)
struct sockaddr_in addr;
struct pf_divert *pd;
+ inp = NULL;
divstat.divs_ipackets++;
if (m->m_len < sizeof(struct ip) &&
(m = m_pullup(m, sizeof(struct ip))) == NULL) {
divstat.divs_errors++;
- return;
+ return (0);
}
pd = pf_find_divert(m);
if (pd == NULL) {
divstat.divs_errors++;
m_freem(m);
- return;
+ return (0);
+ }
+
+ CIRCLEQ_FOREACH(inp, &divbtable.inpt_queue, inp_queue) {
+ if (inp->inp_lport != pd->port)
+ continue;
+ if (inp->inp_divertfl == 0)
+ break;
+ if (dir == PF_IN && !(inp->inp_divertfl & IPPROTO_DIVERT_RESP))
+ return (-1);
+ if (dir == PF_OUT && !(inp->inp_divertfl & IPPROTO_DIVERT_INIT))
+ return (-1);
+ break;
}
bzero(&addr, sizeof(addr));
@@ -177,25 +190,22 @@ divert_packet(struct mbuf *m, int dir)
if (dir == PF_OUT)
in_proto_cksum_out(m, NULL);
- CIRCLEQ_FOREACH(inp, &divbtable.inpt_queue, inp_queue) {
- if (inp->inp_lport != pd->port)
- continue;
-
+ if (inp != CIRCLEQ_END(&divbtable.inpt_queue)) {
sa = inp->inp_socket;
if (sbappendaddr(&sa->so_rcv, (struct sockaddr *)&addr,
m, NULL) == 0) {
divstat.divs_fullsock++;
m_freem(m);
- return;
+ return (0);
} else
sorwakeup(inp->inp_socket);
- break;
}
if (sa == NULL) {
divstat.divs_noport++;
m_freem(m);
}
+ return (0);
}
/*ARGSUSED*/
diff --git a/sys/netinet/ip_divert.h b/sys/netinet/ip_divert.h
index 4e1b05f7695..e2b35a3edb3 100644
--- a/sys/netinet/ip_divert.h
+++ b/sys/netinet/ip_divert.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_divert.h,v 1.3 2009/10/04 16:08:37 michele Exp $ */
+/* $OpenBSD: ip_divert.h,v 1.4 2012/10/21 13:06:03 benno Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -55,7 +55,7 @@ extern struct divstat divstat;
void divert_init(void);
void divert_input(struct mbuf *, ...);
-void divert_packet(struct mbuf *, int);
+int divert_packet(struct mbuf *, int);
int divert_output(struct mbuf *, ...);
int divert_sysctl(int *, u_int, void *, size_t *, void *, size_t);
int divert_usrreq(struct socket *,
diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c
index 91b445d966e..61285a8a4a6 100644
--- a/sys/netinet/raw_ip.c
+++ b/sys/netinet/raw_ip.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: raw_ip.c,v 1.61 2012/03/17 10:16:41 dlg Exp $ */
+/* $OpenBSD: raw_ip.c,v 1.62 2012/10/21 13:06:03 benno Exp $ */
/* $NetBSD: raw_ip.c,v 1.25 1996/02/18 18:58:33 christos Exp $ */
/*
@@ -292,7 +292,8 @@ rip_ctloutput(int op, struct socket *so, int level, int optname,
struct mbuf **m)
{
struct inpcb *inp = sotoinpcb(so);
- int error;
+ int error = 0;
+ int dir;
if (level != IPPROTO_IP) {
if (op == PRCO_SETOPT && *m)
@@ -320,6 +321,39 @@ rip_ctloutput(int op, struct socket *so, int level, int optname,
}
return (error);
+ case IP_DIVERTFL:
+ switch (op) {
+ case PRCO_SETOPT:
+ if (*m == 0 || (*m)->m_len < sizeof (int)) {
+ error = EINVAL;
+ break;
+ }
+ dir = *mtod(*m, int *);
+ if (inp->inp_divertfl > 0)
+ error = ENOTSUP;
+ else if ((dir & IPPROTO_DIVERT_RESP) ||
+ (dir & IPPROTO_DIVERT_INIT))
+ inp->inp_divertfl = dir;
+ else
+ error = EINVAL;
+
+ break;
+
+ case PRCO_GETOPT:
+ *m = m_get(M_WAIT, M_SOOPTS);
+ (*m)->m_len = sizeof(int);
+ *mtod(*m, int *) = inp->inp_divertfl;
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ if (op == PRCO_SETOPT && *m)
+ (void)m_free(*m);
+ return (error);
+
case MRT_INIT:
case MRT_DONE:
case MRT_ADD_VIF:
diff --git a/sys/netinet6/ip6_divert.c b/sys/netinet6/ip6_divert.c
index 2894afafa77..fbc6d9551f5 100644
--- a/sys/netinet6/ip6_divert.c
+++ b/sys/netinet6/ip6_divert.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip6_divert.c,v 1.5 2010/07/03 04:44:51 guenther Exp $ */
+/* $OpenBSD: ip6_divert.c,v 1.6 2012/10/21 13:06:03 benno Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -135,7 +135,7 @@ divert6_output(struct mbuf *m, ...)
return (error);
}
-void
+int
divert6_packet(struct mbuf *m, int dir)
{
struct inpcb *inp;
@@ -143,19 +143,32 @@ divert6_packet(struct mbuf *m, int dir)
struct sockaddr_in6 addr;
struct pf_divert *pd;
+ inp = NULL;
div6stat.divs_ipackets++;
if (m->m_len < sizeof(struct ip6_hdr) &&
(m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) {
div6stat.divs_errors++;
- return;
+ return (0);
}
pd = pf_find_divert(m);
if (pd == NULL) {
div6stat.divs_errors++;
m_freem(m);
- return;
+ return (0);
+ }
+
+ CIRCLEQ_FOREACH(inp, &divb6table.inpt_queue, inp_queue) {
+ if (inp->inp_lport != pd->port)
+ continue;
+ if (inp->inp_divertfl == 0)
+ break;
+ if (dir == PF_IN && !(inp->inp_divertfl & IPPROTO_DIVERT_RESP))
+ return (-1);
+ if (dir == PF_OUT && !(inp->inp_divertfl & IPPROTO_DIVERT_INIT))
+ return (-1);
+ break;
}
bzero(&addr, sizeof(addr));
@@ -176,25 +189,22 @@ divert6_packet(struct mbuf *m, int dir)
}
}
- CIRCLEQ_FOREACH(inp, &divb6table.inpt_queue, inp_queue) {
- if (inp->inp_lport != pd->port)
- continue;
-
+ if (inp != CIRCLEQ_END(&divb6table.inpt_queue)) {
sa = inp->inp_socket;
if (sbappendaddr(&sa->so_rcv, (struct sockaddr *)&addr,
m, NULL) == 0) {
div6stat.divs_fullsock++;
m_freem(m);
- return;
+ return (0);
} else
sorwakeup(inp->inp_socket);
- break;
}
if (sa == NULL) {
div6stat.divs_noport++;
m_freem(m);
}
+ return (0);
}
/*ARGSUSED*/
diff --git a/sys/netinet6/ip6_divert.h b/sys/netinet6/ip6_divert.h
index 47d18320e99..42f32e5c0a6 100644
--- a/sys/netinet6/ip6_divert.h
+++ b/sys/netinet6/ip6_divert.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip6_divert.h,v 1.1 2009/11/05 20:50:14 michele Exp $ */
+/* $OpenBSD: ip6_divert.h,v 1.2 2012/10/21 13:06:03 benno Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -55,7 +55,7 @@ extern struct div6stat div6stat;
void divert6_init(void);
int divert6_input(struct mbuf **, int *, int);
-void divert6_packet(struct mbuf *, int);
+int 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 *,
diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c
index 99de480d0f7..ef353fec29a 100644
--- a/sys/netinet6/raw_ip6.c
+++ b/sys/netinet6/raw_ip6.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: raw_ip6.c,v 1.44 2011/11/24 17:39:55 sperreault Exp $ */
+/* $OpenBSD: raw_ip6.c,v 1.45 2012/10/21 13:06:03 benno Exp $ */
/* $KAME: raw_ip6.c,v 1.69 2001/03/04 15:55:44 itojun Exp $ */
/*
@@ -521,13 +521,46 @@ int
rip6_ctloutput(int op, struct socket *so, int level, int optname,
struct mbuf **mp)
{
-#ifdef MROUTING
+ struct inpcb *inp = sotoinpcb(so);
int error = 0;
-#endif
+ int dir;
switch (level) {
case IPPROTO_IPV6:
switch (optname) {
+
+ case IP_DIVERTFL:
+ switch (op) {
+ case PRCO_SETOPT:
+ if (*mp == 0 || (*mp)->m_len < sizeof (int)) {
+ error = EINVAL;
+ break;
+ }
+ dir = *mtod(*mp, int *);
+ if (inp->inp_divertfl > 0)
+ error = ENOTSUP;
+ else if ((dir & IPPROTO_DIVERT_RESP) ||
+ (dir & IPPROTO_DIVERT_INIT))
+ inp->inp_divertfl = dir;
+ else
+ error = EINVAL;
+ break;
+
+ case PRCO_GETOPT:
+ *mp = m_get(M_WAIT, M_SOOPTS);
+ (*mp)->m_len = sizeof(int);
+ *mtod(*mp, int *) = inp->inp_divertfl;
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ if (op == PRCO_SETOPT && *mp)
+ (void)m_free(*mp);
+ return (error);
+
#ifdef MROUTING
case MRT6_INIT:
case MRT6_DONE: