summaryrefslogtreecommitdiff
path: root/sys/netinet6/ip6_divert.c
diff options
context:
space:
mode:
authorSebastian Benoit <benno@cvs.openbsd.org>2012-10-21 13:06:04 +0000
committerSebastian Benoit <benno@cvs.openbsd.org>2012-10-21 13:06:04 +0000
commit13f32dc0f32386032d455dd5fdf1dfd69753bc9b (patch)
tree7bc9068d988d2f743617f60fc94410b009530734 /sys/netinet6/ip6_divert.c
parent036204675e038878c1b3a43a17ff283b77e9d7ee (diff)
Add the IP_DIVERTFL socket option on divert(4) sockets to control
which packets (as in direction) of the traffic will be diverted through the divert socket. ok claudio@, henning@
Diffstat (limited to 'sys/netinet6/ip6_divert.c')
-rw-r--r--sys/netinet6/ip6_divert.c30
1 files changed, 20 insertions, 10 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*/