summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 2244571..75c1783 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 cce585f..3b77465 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 ed463f0..2e577ad 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 2244571..75c1783 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 0000000..67f5152
--- /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 0000000..67f5152
--- /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 1026672..42e02a5 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 b172d46..c2d0ad7 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 1026672..42e02a5 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 b7ec171..198f6d9 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 0000000..9f3a64e
--- /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 0000000..2b76ac6
--- /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 0000000..776047c
--- /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 0000000..09a4e9f
--- /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 b71e206..7733f32 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 add6eb6..f1134b7 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_ */
OpenPOWER on IntegriCloud