diff options
Diffstat (limited to 'sys/netinet6')
-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 |
3 files changed, 58 insertions, 15 deletions
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: |