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:
parent
35bdac5bbd
commit
a79b71281c
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=61837
@ -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.
|
||||
#
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
133
sys/kern/kern_accf.c
Normal 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
133
sys/kern/uipc_accf.c
Normal 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);
|
||||
}
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 \
|
||||
|
7
sys/modules/accf_data/Makefile
Normal file
7
sys/modules/accf_data/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
# $FreeBSD$
|
||||
|
||||
.PATH: ${.CURDIR}/../../netinet
|
||||
KMOD = accf_data
|
||||
SRCS = accf_data.c
|
||||
|
||||
.include <bsd.kmod.mk>
|
7
sys/modules/accf_http/Makefile
Normal file
7
sys/modules/accf_http/Makefile
Normal 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
80
sys/netinet/accf_data.c
Normal 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
183
sys/netinet/accf_http.c
Normal 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;
|
||||
}
|
@ -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.
|
||||
*/
|
||||
|
@ -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_ */
|
||||
|
Loading…
Reference in New Issue
Block a user