diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/net/pf.c | 9 | ||||
-rw-r--r-- | sys/netinet/in.h | 6 | ||||
-rw-r--r-- | sys/netinet/in_pcb.h | 3 | ||||
-rw-r--r-- | sys/netinet/ip_divert.c | 30 | ||||
-rw-r--r-- | sys/netinet/ip_divert.h | 4 | ||||
-rw-r--r-- | sys/netinet/raw_ip.c | 38 | ||||
-rw-r--r-- | sys/netinet6/ip6_divert.c | 30 | ||||
-rw-r--r-- | sys/netinet6/ip6_divert.h | 4 | ||||
-rw-r--r-- | sys/netinet6/raw_ip6.c | 39 |
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: |