summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichele Marchetto <michele@cvs.openbsd.org>2009-09-08 17:00:42 +0000
committerMichele Marchetto <michele@cvs.openbsd.org>2009-09-08 17:00:42 +0000
commitf2659bb02b244feb1e391d6118ac0dcb0ba6cf41 (patch)
tree367578be996a7aba1066d23891c2fe4274bd6b42
parent202030fc169db12100b9f53a1b16bfb686d53034 (diff)
Add support for divert sockets. They allow you to:
- queue packets from pf(4) to a userspace application - reinject packets from the application into the kernel stack. The divert socket can be bound to a special "divert port" and will receive every packet diverted to that port by pf(4). The pf syntax is pretty simple, e.g.: pass on em0 inet proto tcp from any to any port 80 divert-packet port 8000 test, bugfix and ok by reyk@ manpage help and ok by jmc@ no objections from many others.
-rw-r--r--lib/libc/gen/sysctl.310
-rw-r--r--sbin/pfctl/parse.y19
-rw-r--r--sbin/pfctl/pfctl_parser.c4
-rw-r--r--sbin/sysctl/sysctl.88
-rw-r--r--sbin/sysctl/sysctl.c8
-rw-r--r--share/man/man4/Makefile4
-rw-r--r--share/man/man4/divert.474
-rw-r--r--share/man/man5/pf.conf.510
-rw-r--r--sys/conf/files3
-rw-r--r--sys/net/pf.c20
-rw-r--r--sys/net/pfvar.h6
-rw-r--r--sys/netinet/in.h6
-rw-r--r--sys/netinet/in_proto.c8
-rw-r--r--sys/netinet/ip_divert.c321
-rw-r--r--sys/netinet/ip_divert.h50
-rw-r--r--sys/sys/mbuf.h3
16 files changed, 530 insertions, 24 deletions
diff --git a/lib/libc/gen/sysctl.3 b/lib/libc/gen/sysctl.3
index e6d47ddc9ec..7e40c4c22e5 100644
--- a/lib/libc/gen/sysctl.3
+++ b/lib/libc/gen/sysctl.3
@@ -1,4 +1,4 @@
-.\" $OpenBSD: sysctl.3,v 1.187 2009/06/09 22:24:40 jmc Exp $
+.\" $OpenBSD: sysctl.3,v 1.188 2009/09/08 17:00:40 michele Exp $
.\"
.\" Copyright (c) 1993
.\" The Regents of the University of California. All rights reserved.
@@ -27,7 +27,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd $Mdocdate: June 9 2009 $
+.Dd $Mdocdate: September 8 2009 $
.Dt SYSCTL 3
.Os
.Sh NAME
@@ -1128,6 +1128,8 @@ The currently defined protocols and names are:
.It carp allow integer yes
.It carp log integer yes
.It carp preempt integer yes
+.It divert recvspace integer yes
+.It divert sendspace integer yes
.It esp enable integer yes
.It esp udpencap integer yes
.It esp udpencap_port integer yes
@@ -1240,6 +1242,10 @@ another active master.
If set to any other value, carp will become master of the virtual host if it
believes it can send advertisements more frequently than the current master.
Disabled by default.
+.It Li divert.recvspace
+Returns the default divert receive buffer size.
+.It Li divert.sendspace
+Returns the default divert send buffer size.
.It Li esp.enable
If set to 1, enable the Encapsulating Security Payload
.Pq ESP
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index c7c00b6b92d..f1d52d7e3d8 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.567 2009/09/07 12:21:09 reyk Exp $ */
+/* $OpenBSD: parse.y,v 1.568 2009/09/08 17:00:41 michele Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
@@ -266,7 +266,7 @@ struct filter_opts {
struct {
struct node_host *addr;
u_int16_t port;
- } divert;
+ } divert, divert_packet;
struct redirspec nat;
struct redirspec rdr;
@@ -461,7 +461,7 @@ int parseport(char *, struct range *r, int);
%token STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE
%token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY PFLOW
%token TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE SETTOS
-%token DIVERTTO DIVERTREPLY NATTO RDRTO
+%token DIVERTTO DIVERTREPLY DIVERTPACKET NATTO RDRTO
%token <v.string> STRING
%token <v.number> NUMBER
%token <v.i> PORTBINARY
@@ -2094,6 +2094,7 @@ pfrule : action dir logquick interface af proto fromto
$8.divert.addr->addr.v.a.addr;
}
}
+ r.divert_packet.port = $8.divert_packet.port;
expand_rule(&r, 0, $4, &$8.nat, &$8.rdr, $6, $7.src_os,
$7.src.host, $7.src.port, $7.dst.host, $7.dst.port,
@@ -2227,6 +2228,13 @@ filter_opt : USER uids {
| DIVERTREPLY {
filter_opts.divert.port = 1; /* some random value */
}
+ | DIVERTPACKET PORT portplain {
+ filter_opts.divert_packet.port = $3.a;
+ if (!filter_opts.divert_packet.port) {
+ yyerror("invalid divert port: %u", ntohs($3.a));
+ YYERROR;
+ }
+ }
| SCRUB '(' scrub_opts ')' {
filter_opts.nodf = $3.nodf;
filter_opts.minttl = $3.minttl;
@@ -3914,6 +3922,10 @@ rule_consistent(struct pf_rule *r, int anchor_call)
yyerror("divert is not supported on match rules");
problems++;
}
+ if (r->divert_packet.port) {
+ yyerror("divert is not supported on match rules");
+ problems++;
+ }
if (r->rt) {
yyerror("route-to, reply-to, dup-to and fastroute "
"must not be used on match rules");
@@ -4836,6 +4848,7 @@ lookup(char *s)
{ "code", CODE},
{ "crop", FRAGCROP},
{ "debug", DEBUG},
+ { "divert-packet", DIVERTPACKET},
{ "divert-reply", DIVERTREPLY},
{ "divert-to", DIVERTTO},
{ "drop", DROP},
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c
index dc744ec3d7f..ae5b6c8d235 100644
--- a/sbin/pfctl/pfctl_parser.c
+++ b/sbin/pfctl/pfctl_parser.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl_parser.c,v 1.246 2009/09/02 13:28:03 reyk Exp $ */
+/* $OpenBSD: pfctl_parser.c,v 1.247 2009/09/08 17:00:41 michele Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -1015,6 +1015,8 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose)
printf(" port %u", ntohs(r->divert.port));
}
}
+ if (r->divert_packet.port)
+ printf(" divert-packet port %u", ntohs(r->divert_packet.port));
if (!anchor_call[0] && !TAILQ_EMPTY(&r->nat.list)) {
printf (" nat-to ");
print_pool(&r->nat, r->nat.proxy_port[0],
diff --git a/sbin/sysctl/sysctl.8 b/sbin/sysctl/sysctl.8
index b6066f83b37..734eb67458b 100644
--- a/sbin/sysctl/sysctl.8
+++ b/sbin/sysctl/sysctl.8
@@ -1,4 +1,4 @@
-.\" $OpenBSD: sysctl.8,v 1.149 2009/06/03 21:49:05 beck Exp $
+.\" $OpenBSD: sysctl.8,v 1.150 2009/09/08 17:00:41 michele Exp $
.\" $NetBSD: sysctl.8,v 1.4 1995/09/30 07:12:49 thorpej Exp $
.\"
.\" Copyright (c) 1993
@@ -30,7 +30,7 @@
.\"
.\" @(#)sysctl.8 8.2 (Berkeley) 5/9/95
.\"
-.Dd $Mdocdate: June 3 2009 $
+.Dd $Mdocdate: September 8 2009 $
.Dt SYSCTL 8
.Os
.Sh NAME
@@ -210,6 +210,8 @@ not all of the variables are relevant to all architectures.
.It vm.maxslp integer no
.It vm.uspace integer no
.It fs.posix.setuid integer yes
+.It net.inet.divert.recvspace integer yes
+.It net.inet.divert.sendspace integer yes
.It net.inet.ip.forwarding integer yes
.It net.inet.ip.redirect integer yes
.It net.inet.ip.ttl integer yes
@@ -444,6 +446,8 @@ definitions for third level virtual memory identifiers
.It Aq Pa netinet/in.h
definitions for third level IPv4/v6 identifiers and
fourth level IPv4/v6 identifiers
+.It Aq Pa netinet/ip_divert.h
+definitions for fourth level divert identifiers
.It Aq Pa netinet/icmp_var.h
definitions for fourth level ICMP identifiers
.It Aq Pa netinet6/icmp6.h
diff --git a/sbin/sysctl/sysctl.c b/sbin/sysctl/sysctl.c
index d60686c45d4..de565c46916 100644
--- a/sbin/sysctl/sysctl.c
+++ b/sbin/sysctl/sysctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sysctl.c,v 1.162 2009/08/12 12:26:51 kettenis Exp $ */
+/* $OpenBSD: sysctl.c,v 1.163 2009/09/08 17:00:41 michele Exp $ */
/* $NetBSD: sysctl.c,v 1.9 1995/09/30 07:12:50 thorpej Exp $ */
/*
@@ -40,7 +40,7 @@ static const char copyright[] =
#if 0
static const char sccsid[] = "@(#)sysctl.c 8.5 (Berkeley) 5/9/95";
#else
-static const char rcsid[] = "$OpenBSD: sysctl.c,v 1.162 2009/08/12 12:26:51 kettenis Exp $";
+static const char rcsid[] = "$OpenBSD: sysctl.c,v 1.163 2009/09/08 17:00:41 michele Exp $";
#endif
#endif /* not lint */
@@ -82,6 +82,7 @@ static const char rcsid[] = "$OpenBSD: sysctl.c,v 1.162 2009/08/12 12:26:51 kett
#include <netinet/ip_gre.h>
#include <netinet/ip_ipcomp.h>
#include <netinet/ip_carp.h>
+#include <netinet/ip_divert.h>
#include <net/pfvar.h>
#include <net/if_pfsync.h>
@@ -1322,6 +1323,7 @@ struct ctlname mobileipname[] = MOBILEIPCTL_NAMES;
struct ctlname ipcompname[] = IPCOMPCTL_NAMES;
struct ctlname carpname[] = CARPCTL_NAMES;
struct ctlname pfsyncname[] = PFSYNCCTL_NAMES;
+struct ctlname divertname[] = DIVERTCTL_NAMES;
struct ctlname bpfname[] = CTL_NET_BPF_NAMES;
struct ctlname ifqname[] = CTL_IFQ_NAMES;
struct list inetlist = { inetname, IPPROTO_MAXID };
@@ -1567,7 +1569,7 @@ struct list inetvars[] = {
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
- { 0, 0 },
+ { divertname, DIVERTCTL_MAXID },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
index 5c33311043e..2fd9104c834 100644
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.489 2009/08/12 14:58:34 cnst Exp $
+# $OpenBSD: Makefile,v 1.490 2009/09/08 17:00:41 michele Exp $
MAN= aac.4 ac97.4 acphy.4 \
acpi.4 acpiac.4 acpiasus.4 acpibat.4 acpibtn.4 acpicpu.4 acpidock.4 \
@@ -15,7 +15,7 @@ MAN= aac.4 ac97.4 acphy.4 \
boca.4 bpf.4 brgphy.4 bridge.4 btkbd.4 btms.4 btsco.4 bwi.4 \
cac.4 cas.4 cardbus.4 carp.4 ccd.4 cd.4 cdce.4 cdcef.4 che.4 cfxga.4 \
ch.4 ciphy.4 ciss.4 clcs.4 clct.4 cmpci.4 cnw.4 \
- com.4 crypto.4 cue.4 cy.4 cz.4 dc.4 dcphy.4 ddb.4 de.4 dpt.4 \
+ com.4 crypto.4 cue.4 cy.4 cz.4 dc.4 dcphy.4 ddb.4 de.4 divert.4 dpt.4 \
drm.4 eap.4 ec.4 eephy.4 ef.4 eg.4 ehci.4 eisa.4 el.4 em.4 \
emu.4 enc.4 endrun.4 envy.4 ep.4 epic.4 esa.4 \
eso.4 ess.4 et.4 etphy.4 ex.4 exphy.4 \
diff --git a/share/man/man4/divert.4 b/share/man/man4/divert.4
new file mode 100644
index 00000000000..31c40ef3a4b
--- /dev/null
+++ b/share/man/man4/divert.4
@@ -0,0 +1,74 @@
+.\" $OpenBSD: divert.4,v 1.1 2009/09/08 17:00:41 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.
+.\"
+
+.Dd $Mdocdate: September 8 2009 $
+.Dt DIVERT 4
+.Os
+.Sh NAME
+.Nm divert
+.Nd Kernel packet diversion mechanism
+.Sh SYNOPSIS
+.Fd #include <sys/types.h>
+.Fd #include <sys/socket.h>
+.Fd #include <netinet/in.h>
+.Ft int
+.Fn socket AF_INET SOCK_RAW IPPROTO_DIVERT
+.Sh DESCRIPTION
+Divert sockets can be bound through
+.Xr bind 2
+to a divert port and they will receive every packet
+diverted to that port by
+.Xr pf 4 .
+Consult
+.Xr pf.conf 5
+for the correct syntax.
+Packets can also be reinjected into the divert socket, in which case they
+re-enter kernel packet processing skipping
+.Xr pf 4
+filters, avoiding loops.
+.Pp
+Diverted packets can be read via
+.Xr read 2 ,
+.Xr recv 2 ,
+or
+.Xr recvfrom 2
+from the divert socket.
+.Xr pf 4
+will reassemble the IP packets by default before sending them to the divert
+socket.
+In addition, TCP reassembling can be enabled on a per-rule basis, see
+.Xr pf.conf 5
+for details.
+Writing to a divert socket can be achieved using
+.Xr sendto 2
+and it will skip
+.Xr pf 4
+filters to avoid loops.
+.Pp
+If
+.Xr pf 4
+diverts packets but there are no divert sockets listening,
+the packets are dropped.
+.Sh SEE ALSO
+.Xr socket 2 ,
+.Xr ip 4 ,
+.Xr pf.conf 5 ,
+.Sh HISTORY
+The
+.Nm
+protocol first appeared in
+.Ox 4.7.
diff --git a/share/man/man5/pf.conf.5 b/share/man/man5/pf.conf.5
index db3119b74f2..03fc7409b15 100644
--- a/share/man/man5/pf.conf.5
+++ b/share/man/man5/pf.conf.5
@@ -1,4 +1,4 @@
-.\" $OpenBSD: pf.conf.5,v 1.455 2009/09/07 12:21:10 reyk Exp $
+.\" $OpenBSD: pf.conf.5,v 1.456 2009/09/08 17:00:41 michele Exp $
.\"
.\" Copyright (c) 2002, Daniel Hartmeier
.\" All rights reserved.
@@ -27,7 +27,7 @@
.\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd $Mdocdate: September 7 2009 $
+.Dd $Mdocdate: September 8 2009 $
.Dt PF.CONF 5
.Os
.Sh NAME
@@ -436,6 +436,12 @@ The implicit
rule that is used when a packet does not match any rules does not
allow IP options.
.Pp
+.It Ar divert-packet Aq Ar port
+Used to send matching packets to
+.Xr divert 4
+sockets bound to port
+.Ar port .
+.Pp
.It Ar divert-reply
Used to receive replies for sockets that are bound to addresses
which are not local to the machine.
diff --git a/sys/conf/files b/sys/conf/files
index fe983e3a3a5..a15f4394835 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1,4 +1,4 @@
-# $OpenBSD: files,v 1.474 2009/09/02 18:20:54 thib Exp $
+# $OpenBSD: files,v 1.475 2009/09/08 17:00:41 michele Exp $
# $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
@@ -826,6 +826,7 @@ file netinet/igmp.c inet
file netinet/in.c inet
file netinet/in_pcb.c inet
file netinet/in_proto.c inet
+file netinet/ip_divert.c inet
file netinet/ip_icmp.c inet
file netinet/ip_id.c inet
file netinet/ip_input.c inet
diff --git a/sys/net/pf.c b/sys/net/pf.c
index 607608b3abd..7dbf3c40db9 100644
--- a/sys/net/pf.c
+++ b/sys/net/pf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf.c,v 1.658 2009/09/01 13:42:00 henning Exp $ */
+/* $OpenBSD: pf.c,v 1.659 2009/09/08 17:00:41 michele Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -75,6 +75,7 @@
#include <netinet/udp_var.h>
#include <netinet/icmp_var.h>
#include <netinet/if_ether.h>
+#include <netinet/ip_divert.h>
#include <dev/rndvar.h>
#include <net/pfvar.h>
@@ -5385,6 +5386,9 @@ pf_test(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 here if 1) enabled 2) we deal with a fragment */
h = mtod(m, struct ip *);
if (pf_status.reass && (h->ip_off & htons(IP_MF | IP_OFFMASK)) &&
@@ -5604,6 +5608,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;
struct pf_rule_item *ri;
@@ -5685,6 +5698,11 @@ done:
*m0 = NULL;
action = PF_PASS;
break;
+ case PF_DIVERT:
+ divert_packet(m, dir);
+ *m0 = NULL;
+ action = PF_PASS;
+ break;
default:
/* pf_route can free the mbuf causing *m0 to become NULL */
if (r->rt)
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 5e86421708f..1a7b0029d9d 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfvar.h,v 1.291 2009/09/01 13:42:00 henning Exp $ */
+/* $OpenBSD: pfvar.h,v 1.292 2009/09/08 17:00:41 michele Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -60,7 +60,7 @@ struct ip6_hdr;
enum { PF_INOUT, PF_IN, PF_OUT };
enum { PF_PASS, PF_DROP, PF_SCRUB, PF_NOSCRUB, PF_NAT, PF_NONAT,
PF_BINAT, PF_NOBINAT, PF_RDR, PF_NORDR, PF_SYNPROXY_DROP, PF_DEFER,
- PF_MATCH };
+ PF_MATCH, PF_DIVERT };
enum { PF_RULESET_FILTER, PF_RULESET_NAT, PF_RULESET_BINAT,
PF_RULESET_RDR, PF_RULESET_MAX };
enum { PF_OP_NONE, PF_OP_IRG, PF_OP_EQ, PF_OP_NE, PF_OP_LT,
@@ -622,7 +622,7 @@ struct pf_rule {
struct {
struct pf_addr addr;
u_int16_t port;
- } divert;
+ } divert, divert_packet;
};
/* rule flags */
diff --git a/sys/netinet/in.h b/sys/netinet/in.h
index 3e9256327ba..824ffda78f9 100644
--- a/sys/netinet/in.h
+++ b/sys/netinet/in.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: in.h,v 1.79 2009/06/05 00:05:22 claudio Exp $ */
+/* $OpenBSD: in.h,v 1.80 2009/09/08 17:00:41 michele Exp $ */
/* $NetBSD: in.h,v 1.20 1996/02/13 23:41:47 christos Exp $ */
/*
@@ -74,6 +74,7 @@
#define IPPROTO_IPCOMP 108 /* IP Payload Comp. Protocol */
#define IPPROTO_CARP 112 /* CARP */
#define IPPROTO_PFSYNC 240 /* PFSYNC */
+#define IPPROTO_DIVERT 241 /* Divert sockets */
#define IPPROTO_RAW 255 /* raw IP packet */
#define IPPROTO_MAX 256
@@ -326,7 +327,7 @@ struct ip_mreq {
* Third level is protocol number.
* Fourth level is desired variable within that protocol.
*/
-#define IPPROTO_MAXID (IPPROTO_PFSYNC + 1) /* don't list to IPPROTO_MAX */
+#define IPPROTO_MAXID (IPPROTO_DIVERT + 1) /* don't list to IPPROTO_MAX */
#define CTL_IPPROTO_NAMES { \
{ "ip", CTLTYPE_NODE }, \
@@ -570,6 +571,7 @@ struct ip_mreq {
{ 0, 0 }, \
{ 0, 0 }, \
{ "pfsync", CTLTYPE_NODE }, \
+ { "divert", CTLTYPE_NODE }, \
}
/*
diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c
index 01744b2e59f..b718ad71768 100644
--- a/sys/netinet/in_proto.c
+++ b/sys/netinet/in_proto.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: in_proto.c,v 1.48 2008/05/06 08:47:35 markus Exp $ */
+/* $OpenBSD: in_proto.c,v 1.49 2009/09/08 17:00:41 michele Exp $ */
/* $NetBSD: in_proto.c,v 1.14 1996/02/18 18:58:32 christos Exp $ */
/*
@@ -116,6 +116,7 @@
#include <netinet/ip_var.h>
#include <netinet/ip_icmp.h>
#include <netinet/in_pcb.h>
+#include <netinet/ip_divert.h>
#ifdef INET6
#ifndef INET
@@ -286,6 +287,11 @@ struct protosw inetsw[] = {
0, 0, 0, 0, pfsync_sysctl
},
#endif /* NPFSYNC > 0 */
+{ SOCK_RAW, &inetdomain, IPPROTO_DIVERT, PR_ATOMIC|PR_ADDR,
+ divert_input, 0, 0, 0,
+ divert_usrreq,
+ divert_init, 0, 0, 0, divert_sysctl
+},
/* raw wildcard */
{ SOCK_RAW, &inetdomain, 0, PR_ATOMIC|PR_ADDR,
rip_input, rip_output, 0, rip_ctloutput,
diff --git a/sys/netinet/ip_divert.c b/sys/netinet/ip_divert.c
new file mode 100644
index 00000000000..8614a070c09
--- /dev/null
+++ b/sys/netinet/ip_divert.c
@@ -0,0 +1,321 @@
+/* $OpenBSD: ip_divert.c,v 1.1 2009/09/08 17:00:41 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 <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/ip_divert.h>
+
+#include "pf.h"
+#if NPF > 0
+#include <net/pfvar.h>
+#endif
+
+struct inpcbtable divbtable;
+
+#ifndef DIVERT_SENDSPACE
+#define DIVERT_SENDSPACE (65536 + 100)
+#endif
+u_int divert_sendspace = DIVERT_SENDSPACE;
+#ifndef DIVERT_RECVSPACE
+#define DIVERT_RECVSPACE (65536 + 100)
+#endif
+u_int divert_recvspace = DIVERT_RECVSPACE;
+
+#ifndef DIVERTHASHSIZE
+#define DIVERTHASHSIZE 128
+#endif
+
+int *divertctl_vars[DIVERTCTL_MAXID] = DIVERTCTL_VARS;
+
+int divbhashsize = DIVERTHASHSIZE;
+
+void divert_detach(struct inpcb *);
+
+void
+divert_init()
+{
+ in_pcbinit(&divbtable, divbhashsize);
+}
+
+/* Dummy function, so drop */
+void
+divert_input(struct mbuf *m, ...)
+{
+ m_freem(m);
+}
+
+int
+divert_output(struct mbuf *m, ...)
+{
+ struct inpcb *inp;
+ struct ifqueue *inq;
+ struct mbuf *nam, *control;
+ struct sockaddr_in *sin;
+ 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;
+
+ if (control)
+ m_freem(control);
+
+ sin = mtod(nam, struct sockaddr_in *);
+ so = inp->inp_socket;
+
+ m->m_pkthdr.pf.flags |= PF_TAG_DIVERTED_PACKET;
+
+ if (sin->sin_addr.s_addr != INADDR_ANY) {
+ ifa = ifa_ifwithaddr((struct sockaddr *)sin, 0);
+ if (ifa == NULL) {
+ m_freem(m);
+ return (EADDRNOTAVAIL);
+ }
+ m->m_pkthdr.rcvif = ifa->ifa_ifp;
+
+ inq = &ipintrq;
+
+ s = splnet();
+ IF_INPUT_ENQUEUE(inq, m);
+ schednetisr(NETISR_IP);
+ splx(s);
+ } else {
+ error = ip_output(m, (void *)NULL, &inp->inp_route,
+ ((so->so_options & SO_DONTROUTE) ? IP_ROUTETOIF : 0)
+ | IP_ALLOWBROADCAST | IP_RAWOUTPUT, (void *)NULL,
+ (void *)NULL);
+ }
+
+ return (error);
+}
+
+void
+divert_packet(struct mbuf *m, int dir)
+{
+ struct inpcb *inp;
+ struct socket *sa = NULL;
+ struct sockaddr_in addr;
+ struct pf_divert *pd;
+
+ if (m->m_len < sizeof(struct ip) &&
+ (m = m_pullup(m, sizeof(struct ip))) == NULL)
+ return;
+
+ pd = pf_find_divert(m);
+ if (pd == NULL) {
+ m_freem(m);
+ return;
+ }
+
+ bzero(&addr, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_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_INET)
+ continue;
+ addr.sin_addr.s_addr = ((struct sockaddr_in *)
+ ifa->ifa_addr)->sin_addr.s_addr;
+ break;
+ }
+ }
+
+ CIRCLEQ_FOREACH(inp, &divbtable.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) {
+ m_freem(m);
+ return;
+ } else
+ sorwakeup(inp->inp_socket);
+ break;
+ }
+
+ if (sa == NULL)
+ m_freem(m);
+}
+
+/*ARGSUSED*/
+int
+divert_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 (in_control(so, (u_long)m, (caddr_t)addr,
+ (struct ifnet *)control));
+ }
+ 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, &divbtable);
+ splx(s);
+ if (error)
+ break;
+
+ error = soreserve(so, divert_sendspace, divert_recvspace);
+ if (error)
+ break;
+ ((struct inpcb *) so->so_pcb)->inp_flags |= INP_HDRINCL;
+ break;
+
+ case PRU_DETACH:
+ divert_detach(inp);
+ break;
+
+ case PRU_BIND:
+ s = splsoftnet();
+ error = in_pcbbind(inp, addr, p);
+ splx(s);
+ break;
+
+ case PRU_SHUTDOWN:
+ socantsendmore(so);
+ break;
+
+ case PRU_SEND:
+ return (divert_output(m, inp, addr, control));
+
+ case PRU_ABORT:
+ soisdisconnected(so);
+ divert_detach(inp);
+ break;
+
+ case PRU_SOCKADDR:
+ in_setsockaddr(inp, addr);
+ break;
+
+ case PRU_PEERADDR:
+ in_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("divert_usrreq");
+ }
+
+release:
+ if (control) {
+ m_freem(control);
+ }
+ if (m)
+ m_freem(m);
+ return (error);
+}
+
+void
+divert_detach(struct inpcb *inp)
+{
+ int s = splsoftnet();
+
+ in_pcbdetach(inp);
+ splx(s);
+}
+
+/*
+ * Sysctl for divert variables.
+ */
+int
+divert_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
+ size_t newlen)
+{
+ if (namelen != 1)
+ return (ENOTDIR);
+
+ switch (name[0]) {
+ case DIVERTCTL_SENDSPACE:
+ return (sysctl_int(oldp, oldlenp, newp, newlen,
+ &divert_sendspace));
+ case DIVERTCTL_RECVSPACE:
+ return (sysctl_int(oldp, oldlenp, newp, newlen,
+ &divert_recvspace));
+ default:
+ if (name[0] < DIVERTCTL_MAXID)
+ return sysctl_int_arr(divertctl_vars, name, namelen,
+ oldp, oldlenp, newp, newlen);
+
+ return (ENOPROTOOPT);
+ }
+}
diff --git a/sys/netinet/ip_divert.h b/sys/netinet/ip_divert.h
new file mode 100644
index 00000000000..1dd7a9ec091
--- /dev/null
+++ b/sys/netinet/ip_divert.h
@@ -0,0 +1,50 @@
+/* $OpenBSD: ip_divert.h,v 1.1 2009/09/08 17:00:41 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 _IP_DIVERT_H_
+#define _IP_DIVERT_H_
+
+#define DIVERTCTL_RECVSPACE 1 /* receive buffer space */
+#define DIVERTCTL_SENDSPACE 2 /* send buffer space */
+#define DIVERTCTL_MAXID 3
+
+#define DIVERTCTL_NAMES { \
+ { 0, 0 }, \
+ { "recvspace", CTLTYPE_INT }, \
+ { "sendspace", CTLTYPE_INT } \
+}
+
+#define DIVERTCTL_VARS { \
+ NULL, \
+ &divert_recvspace, \
+ &divert_sendspace \
+}
+
+#ifdef _KERNEL
+extern struct inpcbtable divbtable;
+
+void divert_init(void);
+void divert_input(struct mbuf *, ...);
+void 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 *,
+ int, struct mbuf *, struct mbuf *, struct mbuf *, struct proc *);
+
+#endif /* _KERNEL */
+#endif /* _IP_DIVERT_H_ */
diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h
index ef6e1cbbcf1..109f803842b 100644
--- a/sys/sys/mbuf.h
+++ b/sys/sys/mbuf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: mbuf.h,v 1.133 2009/08/12 20:02:42 dlg Exp $ */
+/* $OpenBSD: mbuf.h,v 1.134 2009/09/08 17:00:41 michele Exp $ */
/* $NetBSD: mbuf.h,v 1.19 1996/02/09 18:25:14 christos Exp $ */
/*
@@ -90,6 +90,7 @@ struct pkthdr_pf {
#define PF_TAG_FRAGCACHE 0x02
#define PF_TAG_TRANSLATE_LOCALHOST 0x04
#define PF_TAG_DIVERTED 0x08
+#define PF_TAG_DIVERTED_PACKET 0x10
/* record/packet header in first mbuf of chain; valid if M_PKTHDR set */
struct pkthdr {