aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorAlfred Perlstein <alfred@FreeBSD.org>2000-06-20 01:09:23 +0000
committerAlfred Perlstein <alfred@FreeBSD.org>2000-06-20 01:09:23 +0000
commita79b71281cd63ad7a6cc43a6d5673a2510b51630 (patch)
tree9aa09a30edf1fe89abe012a7e6a3a40b73b49b32 /sys
parent35bdac5bbd4463b0eb53ccfd8179f479d854bff9 (diff)
downloadsrc-a79b71281cd63ad7a6cc43a6d5673a2510b51630.tar.gz
src-a79b71281cd63ad7a6cc43a6d5673a2510b51630.zip
return of the accept filter part II
accept filters are now loadable as well as able to be compiled into the kernel. two accept filters are provided, one that returns sockets when data arrives the other when an http request is completed (doesn't work with 0.9 requests) Reviewed by: jmg
Notes
Notes: svn path=/head/; revision=61837
Diffstat (limited to 'sys')
-rw-r--r--sys/conf/NOTES4
-rw-r--r--sys/conf/files3
-rw-r--r--sys/conf/options2
-rw-r--r--sys/i386/conf/NOTES4
-rw-r--r--sys/kern/kern_accf.c133
-rw-r--r--sys/kern/uipc_accf.c133
-rw-r--r--sys/kern/uipc_sockbuf.c11
-rw-r--r--sys/kern/uipc_socket.c101
-rw-r--r--sys/kern/uipc_socket2.c11
-rw-r--r--sys/modules/Makefile3
-rw-r--r--sys/modules/accf_data/Makefile7
-rw-r--r--sys/modules/accf_http/Makefile7
-rw-r--r--sys/netinet/accf_data.c80
-rw-r--r--sys/netinet/accf_http.c183
-rw-r--r--sys/sys/socket.h6
-rw-r--r--sys/sys/socketvar.h27
16 files changed, 714 insertions, 1 deletions
diff --git a/sys/conf/NOTES b/sys/conf/NOTES
index 2244571d1c4e..75c1783e29e3 100644
--- a/sys/conf/NOTES
+++ b/sys/conf/NOTES
@@ -541,6 +541,10 @@ options IPFILTER_LOG #ipfilter logging
options IPSTEALTH #support for stealth forwarding
options TCPDEBUG
+# Statically Link in accept filters
+options ACCEPT_FILTER_DATA
+options ACCEPT_FILTER_HTTP
+
# The following options add sysctl variables for controlling how certain
# TCP packets are handled.
#
diff --git a/sys/conf/files b/sys/conf/files
index cce585fbd98b..3b774655d7aa 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -380,6 +380,7 @@ kern/inflate.c optional gzip
kern/init_main.c standard
kern/init_sysent.c standard
kern/kern_acct.c standard
+kern/kern_accf.c standard
kern/kern_acl.c standard
kern/kern_cap.c standard
kern/kern_clock.c standard
@@ -690,6 +691,8 @@ netgraph/ng_tee.c optional netgraph_tee
netgraph/ng_tty.c optional netgraph_tty
netgraph/ng_vjc.c optional netgraph_vjc
net/slcompress.c optional netgraph_vjc
+netinet/accf_data.c optional accept_filter_data
+netinet/accf_http.c optional accept_filter_http
netinet/fil.c optional ipfilter inet
netinet/if_atm.c optional atm
netinet/if_ether.c optional ether
diff --git a/sys/conf/options b/sys/conf/options
index ed463f012899..2e577ad0e964 100644
--- a/sys/conf/options
+++ b/sys/conf/options
@@ -216,6 +216,8 @@ DFLDSIZ opt_rlimit.h
MAXDSIZ opt_rlimit.h
# Net stuff.
+ACCEPT_FILTER_DATA
+ACCEPT_FILTER_HTTP
BOOTP opt_bootp.h
BOOTP_COMPAT opt_bootp.h
BOOTP_NFSROOT opt_bootp.h
diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES
index 2244571d1c4e..75c1783e29e3 100644
--- a/sys/i386/conf/NOTES
+++ b/sys/i386/conf/NOTES
@@ -541,6 +541,10 @@ options IPFILTER_LOG #ipfilter logging
options IPSTEALTH #support for stealth forwarding
options TCPDEBUG
+# Statically Link in accept filters
+options ACCEPT_FILTER_DATA
+options ACCEPT_FILTER_HTTP
+
# The following options add sysctl variables for controlling how certain
# TCP packets are handled.
#
diff --git a/sys/kern/kern_accf.c b/sys/kern/kern_accf.c
new file mode 100644
index 000000000000..67f5152bde0c
--- /dev/null
+++ b/sys/kern/kern_accf.c
@@ -0,0 +1,133 @@
+/*-
+ * Copyright (c) 2000 Alfred Perlstein <alfred@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#define ACCEPT_FILTER_MOD
+
+#include "opt_param.h"
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/domain.h>
+#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/queue.h>
+
+static SLIST_HEAD(, accept_filter) accept_filtlsthd =
+ SLIST_HEAD_INITIALIZER(&accept_filtlsthd);
+
+MALLOC_DEFINE(M_ACCF, "accf", "accept filter data");
+
+/*
+ * must be passed a malloc'd structure so we don't explode if the kld
+ * is unloaded, we leak the struct on deallocation to deal with this,
+ * but if a filter is loaded with the same name as a leaked one we re-use
+ * the entry.
+ */
+int
+accept_filt_add(struct accept_filter *filt)
+{
+ struct accept_filter *p;
+
+ SLIST_FOREACH(p, &accept_filtlsthd, accf_next)
+ if (strcmp(p->accf_name, filt->accf_name) == 0) {
+ if (p->accf_callback != NULL) {
+ return (EEXIST);
+ } else {
+ p->accf_callback = filt->accf_callback;
+ FREE(filt, M_ACCF);
+ return (0);
+ }
+ }
+
+ if (p == NULL)
+ SLIST_INSERT_HEAD(&accept_filtlsthd, filt, accf_next);
+ return (0);
+}
+
+int
+accept_filt_del(char *name)
+{
+ struct accept_filter *p;
+
+ p = accept_filt_get(name);
+ if (p == NULL)
+ return (ENOENT);
+
+ p->accf_callback = NULL;
+ return (0);
+}
+
+struct accept_filter *
+accept_filt_get(char *name)
+{
+ struct accept_filter *p;
+
+ SLIST_FOREACH(p, &accept_filtlsthd, accf_next)
+ if (strcmp(p->accf_name, name) == 0)
+ return (p);
+
+ return (NULL);
+}
+
+int
+accept_filt_generic_mod_event(module_t mod, int event, void *data)
+{
+ struct accept_filter *p;
+ struct accept_filter *accfp = (struct accept_filter *) data;
+ int s, error;
+
+ switch (event) {
+ case MOD_LOAD:
+ MALLOC(p, struct accept_filter *, sizeof(*p), M_ACCF, M_WAITOK);
+ bcopy(accfp, p, sizeof(*p));
+ s = splnet();
+ error = accept_filt_add(p);
+ splx(s);
+ break;
+
+ case MOD_UNLOAD:
+ s = splnet();
+ error = accept_filt_del(accfp->accf_name);
+ splx(s);
+ break;
+
+ case MOD_SHUTDOWN:
+ error = 0;
+ break;
+
+ default:
+ error = EOPNOTSUPP;
+ break;
+ }
+
+ return (error);
+}
diff --git a/sys/kern/uipc_accf.c b/sys/kern/uipc_accf.c
new file mode 100644
index 000000000000..67f5152bde0c
--- /dev/null
+++ b/sys/kern/uipc_accf.c
@@ -0,0 +1,133 @@
+/*-
+ * Copyright (c) 2000 Alfred Perlstein <alfred@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#define ACCEPT_FILTER_MOD
+
+#include "opt_param.h"
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/domain.h>
+#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/queue.h>
+
+static SLIST_HEAD(, accept_filter) accept_filtlsthd =
+ SLIST_HEAD_INITIALIZER(&accept_filtlsthd);
+
+MALLOC_DEFINE(M_ACCF, "accf", "accept filter data");
+
+/*
+ * must be passed a malloc'd structure so we don't explode if the kld
+ * is unloaded, we leak the struct on deallocation to deal with this,
+ * but if a filter is loaded with the same name as a leaked one we re-use
+ * the entry.
+ */
+int
+accept_filt_add(struct accept_filter *filt)
+{
+ struct accept_filter *p;
+
+ SLIST_FOREACH(p, &accept_filtlsthd, accf_next)
+ if (strcmp(p->accf_name, filt->accf_name) == 0) {
+ if (p->accf_callback != NULL) {
+ return (EEXIST);
+ } else {
+ p->accf_callback = filt->accf_callback;
+ FREE(filt, M_ACCF);
+ return (0);
+ }
+ }
+
+ if (p == NULL)
+ SLIST_INSERT_HEAD(&accept_filtlsthd, filt, accf_next);
+ return (0);
+}
+
+int
+accept_filt_del(char *name)
+{
+ struct accept_filter *p;
+
+ p = accept_filt_get(name);
+ if (p == NULL)
+ return (ENOENT);
+
+ p->accf_callback = NULL;
+ return (0);
+}
+
+struct accept_filter *
+accept_filt_get(char *name)
+{
+ struct accept_filter *p;
+
+ SLIST_FOREACH(p, &accept_filtlsthd, accf_next)
+ if (strcmp(p->accf_name, name) == 0)
+ return (p);
+
+ return (NULL);
+}
+
+int
+accept_filt_generic_mod_event(module_t mod, int event, void *data)
+{
+ struct accept_filter *p;
+ struct accept_filter *accfp = (struct accept_filter *) data;
+ int s, error;
+
+ switch (event) {
+ case MOD_LOAD:
+ MALLOC(p, struct accept_filter *, sizeof(*p), M_ACCF, M_WAITOK);
+ bcopy(accfp, p, sizeof(*p));
+ s = splnet();
+ error = accept_filt_add(p);
+ splx(s);
+ break;
+
+ case MOD_UNLOAD:
+ s = splnet();
+ error = accept_filt_del(accfp->accf_name);
+ splx(s);
+ break;
+
+ case MOD_SHUTDOWN:
+ error = 0;
+ break;
+
+ default:
+ error = EOPNOTSUPP;
+ break;
+ }
+
+ return (error);
+}
diff --git a/sys/kern/uipc_sockbuf.c b/sys/kern/uipc_sockbuf.c
index 10266722eab7..42e02a5e41e7 100644
--- a/sys/kern/uipc_sockbuf.c
+++ b/sys/kern/uipc_sockbuf.c
@@ -107,10 +107,21 @@ soisconnected(so)
struct socket *so;
{
struct socket *head = so->so_head;
+ int s;
so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING|SS_ISCONFIRMING);
so->so_state |= SS_ISCONNECTED;
if (head && (so->so_state & SS_INCOMP)) {
+ if ((so->so_options & SO_ACCEPTFILTER) != 0) {
+ s = splnet();
+ so->so_upcall = head->so_accf->so_accept_filter->accf_callback;
+ so->so_upcallarg = head->so_accf->so_accept_filter_arg;
+ so->so_rcv.sb_flags |= SB_UPCALL;
+ so->so_options &= ~SO_ACCEPTFILTER;
+ splx(s);
+ so->so_upcall(so, so->so_upcallarg, 0);
+ return;
+ }
TAILQ_REMOVE(&head->so_incomp, so, so_list);
head->so_incqlen--;
so->so_state &= ~SS_INCOMP;
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
index b172d46b4df1..c2d0ad710d81 100644
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -58,6 +58,8 @@
#include <machine/limits.h>
+static int do_setopt_accept_filter(struct socket *so, struct sockopt *sopt);
+
static int filt_sorattach(struct knote *kn);
static void filt_sordetach(struct knote *kn);
static int filt_soread(struct knote *kn, long hint);
@@ -193,6 +195,15 @@ sodealloc(so)
if (so->so_snd.sb_hiwat)
(void)chgsbsize(so->so_cred->cr_uid,
-(rlim_t)so->so_snd.sb_hiwat);
+ if (so->so_accf != NULL) {
+ if (so->so_accf->so_accept_filter != NULL &&
+ so->so_accf->so_accept_filter->accf_destroy != NULL) {
+ so->so_accf->so_accept_filter->accf_destroy(so);
+ }
+ if (so->so_accf->so_accept_filter_str != NULL)
+ FREE(so->so_accf->so_accept_filter_str, M_ACCF);
+ FREE(so->so_accf, M_ACCF);
+ }
crfree(so->so_cred);
zfreei(so->so_zone, so);
}
@@ -977,6 +988,77 @@ sorflush(so)
sbrelease(&asb, so);
}
+static int
+do_setopt_accept_filter(so, sopt)
+ struct socket *so;
+ struct sockopt *sopt;
+{
+ struct accept_filter_arg *afap = NULL;
+ struct accept_filter *afp;
+ struct so_accf *af = so->so_accf;
+ int error = 0;
+
+ /* removing the filter */
+ if (sopt == NULL) {
+ if (af != NULL) {
+ if (af->so_accept_filter != NULL &&
+ af->so_accept_filter->accf_destroy != NULL) {
+ af->so_accept_filter->accf_destroy(so);
+ }
+ if (af->so_accept_filter_str != NULL) {
+ FREE(af->so_accept_filter_str, M_ACCF);
+ }
+ FREE(af, M_ACCF);
+ so->so_accf = NULL;
+ }
+ so->so_options &= ~SO_ACCEPTFILTER;
+ return (0);
+ }
+ /* adding a filter */
+ /* must remove previous filter first */
+ if (af != NULL) {
+ error = EINVAL;
+ goto out;
+ }
+ /* don't put large objects on the kernel stack */
+ MALLOC(afap, struct accept_filter_arg *, sizeof(*afap), M_TEMP, M_WAITOK);
+ error = sooptcopyin(sopt, afap, sizeof *afap, sizeof *afap);
+ afap->af_name[sizeof(afap->af_name)-1] = '\0';
+ afap->af_arg[sizeof(afap->af_arg)-1] = '\0';
+ if (error)
+ goto out;
+ afp = accept_filt_get(afap->af_name);
+ if (afp == NULL) {
+ error = ENOENT;
+ goto out;
+ }
+ MALLOC(af, struct so_accf *, sizeof(*af), M_ACCF, M_WAITOK);
+ bzero(af, sizeof(*af));
+ if (afp->accf_create != NULL) {
+ if (afap->af_name[0] != '\0') {
+ int len = strlen(afap->af_name) + 1;
+
+ MALLOC(af->so_accept_filter_str, char *, len, M_ACCF, M_WAITOK);
+ strcpy(af->so_accept_filter_str, afap->af_name);
+ }
+ af->so_accept_filter_arg = afp->accf_create(so, afap->af_arg);
+ if (af->so_accept_filter_arg == NULL) {
+ FREE(af->so_accept_filter_str, M_ACCF);
+ FREE(af, M_ACCF);
+ so->so_accf = NULL;
+ error = EINVAL;
+ goto out;
+ }
+ }
+ af->so_accept_filter = afp;
+ so->so_accf = af;
+ so->so_options |= SO_ACCEPTFILTER;
+out:
+ if (afap != NULL)
+ FREE(afap, M_TEMP);
+ return (error);
+}
+
/*
* Perhaps this routine, and sooptcopyout(), below, ought to come in
* an additional variant to handle the case where the option value needs
@@ -1137,6 +1219,11 @@ sosetopt(so, sopt)
}
break;
+ case SO_ACCEPTFILTER:
+ error = do_setopt_accept_filter(so, sopt);
+ if (error)
+ goto bad;
+ break;
default:
error = ENOPROTOOPT;
break;
@@ -1190,6 +1277,7 @@ sogetopt(so, sopt)
int error, optval;
struct linger l;
struct timeval tv;
+ struct accept_filter_arg *afap;
error = 0;
if (sopt->sopt_level != SOL_SOCKET) {
@@ -1200,6 +1288,19 @@ sogetopt(so, sopt)
return (ENOPROTOOPT);
} else {
switch (sopt->sopt_name) {
+ case SO_ACCEPTFILTER:
+ MALLOC(afap, struct accept_filter_arg *, sizeof(*afap),
+ M_TEMP, M_WAITOK);
+ bzero(afap, sizeof(*afap));
+ if ((so->so_options & SO_ACCEPTFILTER) != 0) {
+ strcpy(afap->af_name, so->so_accf->so_accept_filter->accf_name);
+ if (so->so_accf->so_accept_filter_str != NULL)
+ strcpy(afap->af_arg, so->so_accf->so_accept_filter_str);
+ }
+ error = sooptcopyout(sopt, afap, sizeof(*afap));
+ FREE(afap, M_TEMP);
+ break;
+
case SO_LINGER:
l.l_onoff = so->so_options & SO_LINGER;
l.l_linger = so->so_linger;
diff --git a/sys/kern/uipc_socket2.c b/sys/kern/uipc_socket2.c
index 10266722eab7..42e02a5e41e7 100644
--- a/sys/kern/uipc_socket2.c
+++ b/sys/kern/uipc_socket2.c
@@ -107,10 +107,21 @@ soisconnected(so)
struct socket *so;
{
struct socket *head = so->so_head;
+ int s;
so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING|SS_ISCONFIRMING);
so->so_state |= SS_ISCONNECTED;
if (head && (so->so_state & SS_INCOMP)) {
+ if ((so->so_options & SO_ACCEPTFILTER) != 0) {
+ s = splnet();
+ so->so_upcall = head->so_accf->so_accept_filter->accf_callback;
+ so->so_upcallarg = head->so_accf->so_accept_filter_arg;
+ so->so_rcv.sb_flags |= SB_UPCALL;
+ so->so_options &= ~SO_ACCEPTFILTER;
+ splx(s);
+ so->so_upcall(so, so->so_upcallarg, 0);
+ return;
+ }
TAILQ_REMOVE(&head->so_incomp, so, so_list);
head->so_incqlen--;
so->so_state &= ~SS_INCOMP;
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
index b7ec1711d2bb..198f6d96dcd1 100644
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -2,7 +2,8 @@
# XXX present but broken: ip_mroute_mod
-SUBDIR= agp aha amr an aue ccd cd9660 coda cue dc fdesc fxp if_disc if_ef \
+SUBDIR= accf_data accf_http agp aha amr an aue \
+ ccd cd9660 coda cue dc fdesc fxp if_disc if_ef \
if_ppp if_sl if_tun ipfilter ipfw ispfw joy kernfs kue \
md mfs mii mlx msdos ncp netgraph nfs ntfs nullfs \
nwfs oldcard pccard pcic portal procfs rl rp sf sis sk sn ste syscons \
diff --git a/sys/modules/accf_data/Makefile b/sys/modules/accf_data/Makefile
new file mode 100644
index 000000000000..9f3a64ef5213
--- /dev/null
+++ b/sys/modules/accf_data/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../netinet
+KMOD = accf_data
+SRCS = accf_data.c
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/accf_http/Makefile b/sys/modules/accf_http/Makefile
new file mode 100644
index 000000000000..2b76ac6478ae
--- /dev/null
+++ b/sys/modules/accf_http/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../netinet
+KMOD = accf_http
+SRCS = accf_http.c
+
+.include <bsd.kmod.mk>
diff --git a/sys/netinet/accf_data.c b/sys/netinet/accf_data.c
new file mode 100644
index 000000000000..776047ce2dce
--- /dev/null
+++ b/sys/netinet/accf_data.c
@@ -0,0 +1,80 @@
+/*-
+ * Copyright (c) 2000 Alfred Perlstein <alfred@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#define ACCEPT_FILTER_MOD
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysproto.h>
+#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+#include <sys/unistd.h>
+#include <sys/file.h>
+#include <sys/fcntl.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/stat.h>
+#include <sys/mbuf.h>
+#include <sys/resource.h>
+#include <sys/sysent.h>
+#include <sys/resourcevar.h>
+
+/* accept filter that holds a socket until data arrives */
+
+static void sohasdata(struct socket *so, void *arg, int waitflag);
+
+static struct accept_filter accf_data_filter = {
+ "dataready",
+ sohasdata,
+ NULL,
+ NULL
+};
+
+static moduledata_t accf_data_mod = {
+ "accf_data",
+ accept_filt_generic_mod_event,
+ &accf_data_filter
+};
+
+DECLARE_MODULE(accf_data, accf_data_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
+
+static void
+sohasdata(struct socket *so, void *arg, int waitflag)
+{
+
+ if (!soreadable(so)) {
+ return;
+ }
+
+ so->so_upcall = NULL;
+ so->so_rcv.sb_flags &= ~SB_UPCALL;
+ soisconnected(so);
+ return;
+}
diff --git a/sys/netinet/accf_http.c b/sys/netinet/accf_http.c
new file mode 100644
index 000000000000..09a4e9fd6172
--- /dev/null
+++ b/sys/netinet/accf_http.c
@@ -0,0 +1,183 @@
+/*-
+ * Copyright (c) 2000 Alfred Perlstein <alfred@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#define ACCEPT_FILTER_MOD
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysproto.h>
+#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+#include <sys/unistd.h>
+#include <sys/file.h>
+#include <sys/fcntl.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/stat.h>
+#include <sys/mbuf.h>
+#include <sys/resource.h>
+#include <sys/sysent.h>
+#include <sys/resourcevar.h>
+
+/*
+ * XXX: doesn't work with 0.9 requests, make a seperate filter
+ * based on this one if you want to decode those.
+ */
+
+/* check for GET */
+static void sohashttpget(struct socket *so, void *arg, int waitflag);
+/* check for end of HTTP request */
+static void soishttpconnected(struct socket *so, void *arg, int waitflag);
+static char sbindex(struct mbuf **mp, int *begin, int end);
+
+static struct accept_filter accf_http_filter = {
+ "httpready",
+ sohashttpget,
+ NULL,
+ NULL
+};
+
+static moduledata_t accf_http_mod = {
+ "accf_http",
+ accept_filt_generic_mod_event,
+ &accf_http_filter
+};
+
+DECLARE_MODULE(accf_http, accf_http_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
+
+
+static char
+sbindex(struct mbuf **mp, int *begin, int end)
+{
+ struct mbuf *m = *mp;
+ int diff = end - *begin + 1;
+
+ while (m->m_len < diff) {
+ *begin += m->m_len;
+ diff -= m->m_len;
+ if (m->m_next) {
+ m = m->m_next;
+ } else if (m->m_nextpkt) {
+ m = m->m_nextpkt;
+ } else {
+ /* only happens if end > data in socket buffer */
+ panic("sbindex: not enough data");
+ }
+ }
+ *mp = m;
+ return *(mtod(m, char *) + diff - 1);
+}
+
+static void
+sohashttpget(struct socket *so, void *arg, int waitflag)
+{
+
+ if ((so->so_state & SS_CANTRCVMORE) == 0) {
+ struct mbuf *m;
+
+ if (so->so_rcv.sb_cc < 6)
+ return;
+ m = so->so_rcv.sb_mb;
+ if (bcmp(mtod(m, char *), "GET ", 4) == 0) {
+ soishttpconnected(so, arg, waitflag);
+ return;
+ }
+ }
+
+ so->so_upcall = NULL;
+ so->so_rcv.sb_flags &= ~SB_UPCALL;
+ soisconnected(so);
+ return;
+}
+
+static void
+soishttpconnected(struct socket *so, void *arg, int waitflag)
+{
+ char a, b, c;
+ struct mbuf *y, *z;
+
+ if ((so->so_state & SS_CANTRCVMORE) == 0) {
+ /* seek to end and keep track of next to last mbuf */
+ y = so->so_rcv.sb_mb;
+ while (y->m_nextpkt)
+ y = y->m_nextpkt;
+ z = y;
+ while (y->m_next) {
+ z = y;
+ y = y->m_next;
+ }
+
+ if (z->m_len + y->m_len > 2) {
+ int index = y->m_len - 1;
+
+ c = *(mtod(y, char *) + index--);
+ switch (index) {
+ case -1:
+ y = z;
+ index = y->m_len - 1;
+ b = *(mtod(y, char *) + index--);
+ break;
+ case 0:
+ b = *(mtod(y, char *) + index--);
+ y = z;
+ index = y->m_len - 1;
+ break;
+ default:
+ b = *(mtod(y, char *) + index--);
+ break;
+ }
+ a = *(mtod(y, char *) + index--);
+ } else {
+ int begin = 0;
+ int end = so->so_rcv.sb_cc - 3;
+
+ y = so->so_rcv.sb_mb;
+ a = sbindex(&y, &begin, end++);
+ b = sbindex(&y, &begin, end++);
+ c = sbindex(&y, &begin, end++);
+ }
+
+ if (c == '\n' && (b == '\n' || (b == '\r' && a == '\n'))) {
+ /* we have all request headers */
+ goto done;
+ } else {
+ /* still need more data */
+ so->so_upcall = soishttpconnected;
+ so->so_rcv.sb_flags |= SB_UPCALL;
+ return;
+ }
+ }
+
+done:
+ so->so_upcall = NULL;
+ so->so_rcv.sb_flags &= ~SB_UPCALL;
+ soisconnected(so);
+ return;
+}
diff --git a/sys/sys/socket.h b/sys/sys/socket.h
index b71e206c61c5..7733f32bc703 100644
--- a/sys/sys/socket.h
+++ b/sys/sys/socket.h
@@ -70,6 +70,7 @@ typedef u_int32_t socklen_t;
#define SO_OOBINLINE 0x0100 /* leave received OOB data in line */
#define SO_REUSEPORT 0x0200 /* allow local address & port reuse */
#define SO_TIMESTAMP 0x0400 /* timestamp received dgram traffic */
+#define SO_ACCEPTFILTER 0x1000 /* there is an accept filter */
/*
* Additional options, not kept in so_options.
@@ -92,6 +93,11 @@ struct linger {
int l_linger; /* linger time */
};
+struct accept_filter_arg {
+ char af_name[16];
+ char af_arg[256-16];
+};
+
/*
* Level number for (get/set)sockopt() to apply to socket itself.
*/
diff --git a/sys/sys/socketvar.h b/sys/sys/socketvar.h
index add6eb6c988e..f1134b774259 100644
--- a/sys/sys/socketvar.h
+++ b/sys/sys/socketvar.h
@@ -48,6 +48,8 @@
*/
typedef u_quad_t so_gen_t;
+struct accept_filter;
+
struct socket {
struct vm_zone *so_zone; /* zone we were allocated from */
short so_type; /* generic type, see socket.h */
@@ -112,6 +114,11 @@ struct socket {
/* NB: generation count must not be first; easiest to make it last. */
so_gen_t so_gencnt; /* generation count */
void *so_emuldata; /* private data for emulators */
+ struct so_accf {
+ struct accept_filter *so_accept_filter;
+ void *so_accept_filter_arg; /* saved filter args */
+ char *so_accept_filter_str; /* saved user args */
+ } *so_accf;
};
/*
@@ -270,9 +277,21 @@ struct sf_buf {
vm_offset_t kva; /* va of mapping */
};
+struct accept_filter {
+ char accf_name[16];
+ void (*accf_callback)
+ __P((struct socket *so, void *arg, int waitflag));
+ void * (*accf_create)
+ __P((struct socket *so, char *arg));
+ void (*accf_destroy)
+ __P((struct socket *so));
+ SLIST_ENTRY(accept_filter) accf_next; /* next on the list */
+};
+
#ifdef MALLOC_DECLARE
MALLOC_DECLARE(M_PCB);
MALLOC_DECLARE(M_SONAME);
+MALLOC_DECLARE(M_ACCF);
#endif
extern int maxsockets;
@@ -380,6 +399,14 @@ int soshutdown __P((struct socket *so, int how));
void sotoxsocket __P((struct socket *so, struct xsocket *xso));
void sowakeup __P((struct socket *so, struct sockbuf *sb));
+/* accept filter functions */
+int accept_filt_add __P((struct accept_filter *filt));
+int accept_filt_del __P((char *name));
+struct accept_filter * accept_filt_get __P((char *name));
+#ifdef ACCEPT_FILTER_MOD
+int accept_filt_generic_mod_event __P((module_t mod, int event, void *data));
+#endif /* ACCEPT_FILTER_MOD */
+
#endif /* _KERNEL */
#endif /* !_SYS_SOCKETVAR_H_ */