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
This commit is contained in:
Alfred Perlstein 2000-06-20 01:09:23 +00:00
parent 35bdac5bbd
commit a79b71281c
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=61837
16 changed files with 714 additions and 1 deletions

View File

@ -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.
#

View File

@ -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

View File

@ -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

View File

@ -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.
#

133
sys/kern/kern_accf.c Normal file
View File

@ -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);
}

133
sys/kern/uipc_accf.c Normal file
View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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 \

View File

@ -0,0 +1,7 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../netinet
KMOD = accf_data
SRCS = accf_data.c
.include <bsd.kmod.mk>

View File

@ -0,0 +1,7 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../netinet
KMOD = accf_http
SRCS = accf_http.c
.include <bsd.kmod.mk>

80
sys/netinet/accf_data.c Normal file
View File

@ -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;
}

183
sys/netinet/accf_http.c Normal file
View File

@ -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;
}

View File

@ -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.
*/

View File

@ -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_ */