Discussion:
Patch: accept filters for NetBSD
(too old to reply)
Thor Lancelot Simon
2008-01-28 21:30:10 UTC
Permalink
A coworker has ported the FreeBSD "accept filter" functionality to
NetBSD (approximately 4.99.40 -- I think the attached patch should
apply cleanly to HEAD today, however). Accept filters are kernel
level filters, enabled with setsockopt(), which can perform arbitrary
operations on a TCP or local stream connection before accept() returns
to userspace or the listen socket selects ready for accept. Think of
it as a much more sophisticated version of the socket watermark.

These have been in FreeBSD for a long time. In FreeBSD they're often
dynamically loaded just before the setsockopt() but doing so at runtime
poses some obvious security issues. We didn't adapt the kernel-module
code in this patch to the new NetBSD framework but will do so over time
if these are committed. Rather, we've made each accept filter (we
supply two, "dataready" and "http") a pseudo-device to allow static
configuration in the kernel config file; in my opinion this is moderately
hokey but it works and is less objectionable than any of my other ideas.

Opinions? The manual pages (accept_filter, accf_http, accf_dataready)
are not present in the patch but I will adjust them for NetBSD and
check them in with the rest of this if there are no objections.
--
Thor Lancelot Simon
Coyote Point Systems, Inc. <***@coyotepoint.com>
Millerton, NY, USA

--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Thor Lancelot Simon
2008-01-28 21:34:00 UTC
Permalink
Post by Thor Lancelot Simon
A coworker has ported the FreeBSD "accept filter" functionality to
NetBSD (approximately 4.99.40 -- I think the attached patch should
apply cleanly to HEAD today, however).
Oops! Here's the patch.

--- /workspaces/vendor/nbsrc/sys/conf/files 2008-01-09 14:44:14.000000000 -0500
+++ sys/conf/files 2008-01-28 16:01:14.000000000 -0500
@@ -1188,6 +1188,9 @@
defpseudo carp: ifnet, ether, arp, bpf_filter
defpseudo etherip { }: ifnet, ether, arp, bpf_filter

+defpseudo accf_data
+defpseudo accf_http
+
defpseudo sequencer
defpseudo clockctl
defpseudo irix_kmem
@@ -1422,6 +1425,7 @@
file kern/tty_ptm.c pty
file kern/tty_subr.c
file kern/tty_tty.c
+file kern/uipc_accf.c inet
file kern/uipc_domain.c
file kern/uipc_mbuf.c
file kern/uipc_mbuf2.c
@@ -1506,6 +1510,8 @@
file netinet/ip_etherip.c etherip & inet
file netinet6/ip6_etherip.c etherip & inet6
file netinet6/in6_gif.c gif & inet6
+file netinet/accf_data.c inet & accf_data
+file netinet/accf_http.c inet & accf_http

file netisdn/i4b_ctl.c isdnctl needs-flag
file netisdn/i4b_isppp.c ippp needs-count
@@ -1559,3 +1565,6 @@
# Pseudo audio device
#
include "dev/pad/files.pad"
+# Coyote Point Equalizer
+#
+include "l7lb/files.EQ"
--- /dev/null 2008-01-28 15:53:44.000000000 -0500
+++ sys/kern/uipc_accf.c 2008-01-28 16:01:30.000000000 -0500
@@ -0,0 +1,301 @@
+/*-
+ * Copyright (c) 2000 Paycounter, Inc.
+ * Copyright (c) 2005 Robert N. M. Watson
+ * Author: Alfred Perlstein <***@paycounter.com>, <***@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.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: uipc_accf.c $");
+
+#define ACCEPT_FILTER_MOD
+
+#include "opt_inet.h"
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/domain.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/lkm.h>
+#include <sys/mutex.h>
+#include <sys/protosw.h>
+#include <sys/sysctl.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");
+
+static int unloadable = 0;
+
+/*
+ * Names of Accept filter sysctl objects
+ */
+
+#define ACCFCTL_UNLOADABLE 1 /* Allow module to be unloaded */
+
+
+SYSCTL_SETUP(sysctl_net_inet_accf_setup, "sysctl net.inet.accf subtree setup")
+{
+ sysctl_createv(clog, 0, NULL, NULL,
+ CTLFLAG_PERMANENT,
+ CTLTYPE_NODE, "net", NULL,
+ NULL, 0, NULL, 0,
+ CTL_NET, CTL_EOL);
+ sysctl_createv(clog, 0, NULL, NULL,
+ CTLFLAG_PERMANENT,
+ CTLTYPE_NODE, "inet", NULL,
+ NULL, 0, NULL, 0,
+ CTL_NET, PF_INET, CTL_EOL);
+ sysctl_createv(clog, 0, NULL, NULL,
+ CTLFLAG_PERMANENT,
+ CTLTYPE_NODE, "accf",
+ SYSCTL_DESCR("Accept filters"),
+ NULL, 0, NULL, 0,
+ CTL_NET, PF_INET, SO_ACCEPTFILTER, CTL_EOL);
+ sysctl_createv(clog, 0, NULL, NULL,
+ CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+ CTLTYPE_INT, "unloadable",
+ SYSCTL_DESCR("Allow unload of accept filters "
+ "(not recommended)"),
+ NULL, 0, &unloadable, 0,
+ CTL_NET, PF_INET, SO_ACCEPTFILTER,
+ ACCFCTL_UNLOADABLE, CTL_EOL);
+}
+
+/*
+ * 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)
+ break;
+
+ return (p);
+}
+
+int
+accept_filt_generic_mod_event(struct lkm_table *lkmtp, int event, void *data)
+{
+ struct accept_filter *p;
+ struct accept_filter *accfp = (struct accept_filter *) data;
+ int error;
+
+ switch (event) {
+ case LKM_E_LOAD:
+ MALLOC(p, struct accept_filter *, sizeof(*p), M_ACCF,
+ M_WAITOK);
+ bcopy(accfp, p, sizeof(*p));
+ error = accept_filt_add(p);
+ break;
+
+ case LKM_E_UNLOAD:
+ /*
+ * Do not support unloading yet. we don't keep track of
+ * refcounts and unloading an accept filter callback and then
+ * having it called is a bad thing. A simple fix would be to
+ * track the refcount in the struct accept_filter.
+ */
+ if (unloadable != 0) {
+ error = accept_filt_del(accfp->accf_name);
+ } else
+ error = EOPNOTSUPP;
+ break;
+
+ case LKM_E_STAT:
+ error = 0;
+ break;
+
+ default:
+ error = EOPNOTSUPP;
+ break;
+ }
+
+ return (error);
+}
+
+int
+do_getopt_accept_filter(struct socket *so, struct mbuf *m)
+{
+ int error;
+
+ error = 0;
+ if ((so->so_options & SO_ACCEPTCONN) == 0) {
+ error = EINVAL;
+ goto out;
+ }
+ if ((so->so_options & SO_ACCEPTFILTER) == 0) {
+ error = EINVAL;
+ goto out;
+ }
+ m->m_len = sizeof(struct accept_filter_arg);
+ strcpy(mtod(m, struct accept_filter_arg *)->af_name, so->so_accf->so_accept_filter->accf_name);
+ if (so->so_accf->so_accept_filter_str != NULL)
+ strcpy(mtod(m, struct accept_filter_arg *)->af_arg, so->so_accf->so_accept_filter_str);
+out:
+ return (error);
+}
+
+int
+do_setopt_accept_filter(struct socket *so, struct mbuf *m)
+{
+ struct accept_filter_arg *afap;
+ struct accept_filter *afp;
+ struct so_accf *newaf;
+ int error = 0;
+
+ /*
+ * Handle the simple delete case first.
+ */
+ if (m == NULL || mtod(m, struct accept_filter_arg *) == NULL) {
+ if ((so->so_options & SO_ACCEPTCONN) == 0) {
+ return (EINVAL);
+ }
+ if (so->so_accf != NULL) {
+ struct so_accf *af = so->so_accf;
+ 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);
+ }
+
+ /*
+ * Pre-allocate any memory we may need later to avoid blocking at
+ * untimely moments. This does not optimize for invalid arguments.
+ */
+ if (m->m_len != sizeof(struct accept_filter_arg)) {
+ return (EINVAL);
+ }
+ afap = mtod(m, struct accept_filter_arg *);
+ afap->af_name[sizeof(afap->af_name)-1] = '\0';
+ afap->af_arg[sizeof(afap->af_arg)-1] = '\0';
+ if (error) {
+ return (error);
+ }
+ afp = accept_filt_get(afap->af_name);
+ if (afp == NULL) {
+ return (ENOENT);
+ }
+ /*
+ * Allocate the new accept filter instance storage. We may
+ * have to free it again later if we fail to attach it. If
+ * attached properly, 'newaf' is NULLed to avoid a free()
+ * while in use.
+ */
+ MALLOC(newaf, struct so_accf *, sizeof(*newaf), M_ACCF, M_WAITOK |
+ M_ZERO);
+ if (afp->accf_create != NULL && afap->af_name[0] != '\0') {
+ int len = strlen(afap->af_name) + 1;
+ MALLOC(newaf->so_accept_filter_str, char *, len, M_ACCF,
+ M_WAITOK);
+ strcpy(newaf->so_accept_filter_str, afap->af_name);
+ }
+
+ /*
+ * Require a listen socket; don't try to replace an existing filter
+ * without first removing it.
+ */
+ if (((so->so_options & SO_ACCEPTCONN) == 0) ||
+ (so->so_accf != NULL)) {
+ error = EINVAL;
+ goto out;
+ }
+
+ /*
+ * Invoke the accf_create() method of the filter if required. The
+ * socket mutex is held over this call, so create methods for filters
+ * can't block.
+ */
+ if (afp->accf_create != NULL) {
+ newaf->so_accept_filter_arg =
+ afp->accf_create(so, afap->af_arg);
+ if (newaf->so_accept_filter_arg == NULL) {
+ error = EINVAL;
+ goto out;
+ }
+ }
+ newaf->so_accept_filter = afp;
+ so->so_accf = newaf;
+ so->so_options |= SO_ACCEPTFILTER;
+ newaf = NULL;
+out:
+ if (newaf != NULL) {
+ if (newaf->so_accept_filter_str != NULL)
+ FREE(newaf->so_accept_filter_str, M_ACCF);
+ FREE(newaf, M_ACCF);
+ }
+ return (error);
+}
--- /workspaces/vendor/nbsrc/sys/kern/uipc_socket.c 2008-01-09 14:44:39.000000000 -0500
+++ sys/kern/uipc_socket.c 2008-01-28 16:01:30.000000000 -0500
@@ -70,6 +70,7 @@
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uipc_socket.c,v 1.149 2007/12/05 17:19:59 pooka Exp $");

+#include "opt_inet.h"
#include "opt_sock_counters.h"
#include "opt_sosend_loan.h"
#include "opt_mbuftrace.h"
@@ -625,6 +626,11 @@
sorflush(so);
seldestroy(&so->so_rcv.sb_sel);
seldestroy(&so->so_snd.sb_sel);
+#ifdef INET
+ /* remove acccept filter if one is present. */
+ if (so->so_accf != NULL)
+ do_setopt_accept_filter(so, NULL);
+#endif
pool_put(&socket_pool, so);
}

@@ -1460,13 +1466,25 @@
static int
sosetopt1(struct socket *so, int level, int optname, struct mbuf *m)
{
+#ifdef INET
+ int error, optval, val;
+#else
int optval, val;
+#endif
struct linger *l;
struct sockbuf *sb;
struct timeval *tv;

switch (optname) {

+#ifdef INET
+ case SO_ACCEPTFILTER:
+ error = do_setopt_accept_filter(so, m);
+ if (error)
+ return error;
+ break;
+#endif
+
case SO_LINGER:
if (m == NULL || m->m_len != sizeof(struct linger))
return EINVAL;
@@ -1596,6 +1614,9 @@
int
sogetopt(struct socket *so, int level, int optname, struct mbuf **mp)
{
+#ifdef INET
+ int error;
+#endif
struct mbuf *m;

if (level != SOL_SOCKET) {
@@ -1610,6 +1631,14 @@

switch (optname) {

+#ifdef INET
+ case SO_ACCEPTFILTER:
+ error = do_getopt_accept_filter(so, m);
+ if (error)
+ return error;
+ break;
+#endif
+
case SO_LINGER:
m->m_len = sizeof(struct linger);
mtod(m, struct linger *)->l_onoff =
--- /workspaces/vendor/nbsrc/sys/kern/uipc_socket2.c 2008-01-09 14:44:39.000000000 -0500
+++ sys/kern/uipc_socket2.c 2008-01-28 16:01:30.000000000 -0500
@@ -34,6 +34,7 @@
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uipc_socket2.c,v 1.86 2007/09/25 14:04:07 ad Exp $");

+#include "opt_inet.h"
#include "opt_mbuftrace.h"
#include "opt_sb_max.h"

@@ -110,10 +111,20 @@
head = so->so_head;
so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING|SS_ISCONFIRMING);
so->so_state |= SS_ISCONNECTED;
- if (head && soqremque(so, 0)) {
- soqinsque(head, so, 1);
- sorwakeup(head);
- wakeup((void *)&head->so_timeo);
+ if (head && so->so_onq == &head->so_q0) {
+ if ((so->so_options & SO_ACCEPTFILTER) == 0) {
+ soqremque(so, 0);
+ soqinsque(head, so, 1);
+ sorwakeup(head);
+ wakeup((void *)&head->so_timeo);
+ } else {
+ 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;
+ so->so_upcall(so, so->so_upcallarg, M_DONTWAIT);
+ }
} else {
wakeup((void *)&so->so_timeo);
sorwakeup(so);
@@ -157,6 +168,8 @@
struct socket *so;
int soqueue;

+ if ((head->so_options & SO_ACCEPTFILTER) != 0)
+ connstatus = 0;
soqueue = connstatus ? 1 : 0;
if (head->so_qlen + head->so_q0len > 3 * head->so_qlimit / 2)
return ((struct socket *)0);
@@ -195,6 +208,11 @@
(void) soqremque(so, soqueue);
seldestroy(&so->so_rcv.sb_sel);
seldestroy(&so->so_snd.sb_sel);
+#ifdef INET
+ /* remove acccept filter if one is present. */
+ if (so->so_accf != NULL)
+ do_setopt_accept_filter(so, NULL);
+#endif
pool_put(&socket_pool, so);
return (NULL);
}
--- /dev/null 2008-01-28 15:53:44.000000000 -0500
+++ sys/netinet/accept_filter.h 2008-01-28 16:01:33.000000000 -0500
@@ -0,0 +1,50 @@
+/* $NetBSD: accept_filter.h $ */
+
+/*
+ * Copyright (c) 2006 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Rui Paulo.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#ifndef _NETINET_ACCEPT_FILTER_H
+#define _NETINET_ACCEPT_FILTER_H
+
+/*
+ * Valid accept filter list
+ * Currently it is used for creting sysctl object
+ */
+
+#define ACCF_DATA 1 /* Data ready accept filter */
+#define ACCF_HTTP 2 /* HTTP ready accept filter */
+
+#endif /* _NETINET_ACCEPT_FILTER_H */
--- /dev/null 2008-01-28 15:53:44.000000000 -0500
+++ sys/netinet/accf_data.c 2008-01-28 16:01:33.000000000 -0500
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 2000 Alfred Perlstein <***@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.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: accf_data.c $");
+
+#define ACCEPT_FILTER_MOD
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/lkm.h>
+#include <sys/sysctl.h>
+#include <sys/signalvar.h>
+#include <sys/socketvar.h>
+#include <netinet/accept_filter.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,
+ {NULL,}
+};
+
+void accf_dataattach(int);
+void accf_dataattach(int num)
+{
+ accept_filt_generic_mod_event(NULL, LKM_E_LOAD, &accf_data_filter);
+}
+
+#ifdef _LKM
+static int accf_data_handle(struct lkm_table * lkmtp, int cmd);
+int accf_data_lkmentry(struct lkm_table * lkmtp, int cmd, int ver);
+
+MOD_MISC("accf_data");
+
+static int accf_data_handle(struct lkm_table * lkmtp, int cmd)
+{
+
+ printf("called this funtion\n");
+ return accept_filt_generic_mod_event(lkmtp, cmd, &accf_data_filter);
+}
+
+/*
+ * the module entry point.
+ */
+int
+accf_data_lkmentry(struct lkm_table *lkmtp, int cmd, int ver)
+{
+ DISPATCH(lkmtp, cmd, ver, accf_data_handle, accf_data_handle,
+ accf_data_handle)
+}
+#endif
+
+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;
+}
--- /dev/null 2008-01-28 15:53:44.000000000 -0500
+++ sys/netinet/accf_http.c 2008-01-28 16:01:33.000000000 -0500
@@ -0,0 +1,421 @@
+/*-
+ * Copyright (c) 2000 Paycounter, Inc.
+ * Author: Alfred Perlstein <***@paycounter.com>, <***@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.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: accf_data.c $");
+
+#define ACCEPT_FILTER_MOD
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/lkm.h>
+#include <sys/signalvar.h>
+#include <sys/sysctl.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <netinet/accept_filter.h>
+
+/* check for GET/HEAD */
+static void sohashttpget(struct socket *so, void *arg, int waitflag);
+/* check for HTTP/1.0 or HTTP/1.1 */
+static void soparsehttpvers(struct socket *so, void *arg, int waitflag);
+/* check for end of HTTP/1.x request */
+static void soishttpconnected(struct socket *so, void *arg, int waitflag);
+/* strcmp on an mbuf chain */
+static int mbufstrcmp(struct mbuf *m, struct mbuf *npkt, int offset, const char *cmp);
+/* strncmp on an mbuf chain */
+static int mbufstrncmp(struct mbuf *m, struct mbuf *npkt, int offset,
+ int len, const char *cmp);
+/* socketbuffer is full */
+static int sbfull(struct sockbuf *sb);
+
+static struct accept_filter accf_http_filter = {
+ "httpready",
+ sohashttpget,
+ NULL,
+ NULL,
+ {NULL,}
+};
+
+/*
+ * Names of HTTP Accept filter sysctl objects
+ */
+
+#define ACCFCTL_PARSEVER 1 /* Parse HTTP version */
+
+static int parse_http_version = 1;
+
+SYSCTL_SETUP(sysctl_net_inet_accf__http_setup, "sysctl net.inet.accf.http subtree setup")
+{
+ sysctl_createv(clog, 0, NULL, NULL,
+ CTLFLAG_PERMANENT,
+ CTLTYPE_NODE, "net", NULL,
+ NULL, 0, NULL, 0,
+ CTL_NET, CTL_EOL);
+ sysctl_createv(clog, 0, NULL, NULL,
+ CTLFLAG_PERMANENT,
+ CTLTYPE_NODE, "inet", NULL,
+ NULL, 0, NULL, 0,
+ CTL_NET, PF_INET, CTL_EOL);
+ sysctl_createv(clog, 0, NULL, NULL,
+ CTLFLAG_PERMANENT,
+ CTLTYPE_NODE, "accf", NULL,
+ NULL, 0, NULL, 0,
+ CTL_NET, PF_INET, SO_ACCEPTFILTER, CTL_EOL);
+ sysctl_createv(clog, 0, NULL, NULL,
+ CTLFLAG_PERMANENT,
+ CTLTYPE_NODE, "http",
+ SYSCTL_DESCR("HTTP accept filter"),
+ NULL, 0, NULL, 0,
+ CTL_NET, PF_INET, SO_ACCEPTFILTER, ACCF_HTTP, CTL_EOL);
+ sysctl_createv(clog, 0, NULL, NULL,
+ CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+ CTLTYPE_INT, "parsehttpversion",
+ SYSCTL_DESCR("Parse http version so that non "
+ "1.x requests work"),
+ NULL, 0, &parse_http_version, 0,
+ CTL_NET, PF_INET, SO_ACCEPTFILTER, ACCF_HTTP,
+ ACCFCTL_PARSEVER, CTL_EOL);
+}
+
+void accf_httpattach(int);
+void accf_httpattach(int num)
+{
+ accept_filt_generic_mod_event(NULL, LKM_E_LOAD, &accf_http_filter);
+}
+
+#ifdef _LKM
+static int accf_http_handle(struct lkm_table * lkmtp, int cmd);
+int accf_http_lkmentry(struct lkm_table * lkmtp, int cmd, int ver);
+
+MOD_MISC("accf_http");
+
+static int accf_http_handle(struct lkm_table * lkmtp, int cmd)
+{
+
+ return accept_filt_generic_mod_event(lkmtp, cmd, &accf_http_filter);
+}
+
+/*
+ * the module entry point.
+ */
+int
+accf_http_lkmentry(struct lkm_table *lkmtp, int cmd, int ver)
+{
+ DISPATCH(lkmtp, cmd, ver, accf_http_handle, accf_http_handle,
+ accf_http_handle)
+}
+#endif
+
+
+
+#ifdef ACCF_HTTP_DEBUG
+#define DPRINT(fmt, args...) \
+ do { \
+ printf("%s:%d: " fmt "\n", __func__, __LINE__, ##args); \
+ } while (0)
+#else
+#define DPRINT(fmt, args...)
+#endif
+
+static int
+sbfull(struct sockbuf *sb)
+{
+
+ DPRINT("sbfull, cc(%ld) >= hiwat(%ld): %d, "
+ "mbcnt(%ld) >= mbmax(%ld): %d",
+ sb->sb_cc, sb->sb_hiwat, sb->sb_cc >= sb->sb_hiwat,
+ sb->sb_mbcnt, sb->sb_mbmax, sb->sb_mbcnt >= sb->sb_mbmax);
+ return (sb->sb_cc >= sb->sb_hiwat || sb->sb_mbcnt >= sb->sb_mbmax);
+}
+
+/*
+ * start at mbuf m, (must provide npkt if exists)
+ * starting at offset in m compare characters in mbuf chain for 'cmp'
+ */
+static int
+mbufstrcmp(struct mbuf *m, struct mbuf *npkt, int offset, const char *cmp)
+{
+ struct mbuf *n;
+
+ for (; m != NULL; m = n) {
+ n = npkt;
+ if (npkt)
+ npkt = npkt->m_nextpkt;
+ for (; m; m = m->m_next) {
+ for (; offset < m->m_len; offset++, cmp++) {
+ if (*cmp == '\0')
+ return (1);
+ else if (*cmp != *(mtod(m, char *) + offset))
+ return (0);
+ }
+ if (*cmp == '\0')
+ return (1);
+ offset = 0;
+ }
+ }
+ return (0);
+}
+
+/*
+ * start at mbuf m, (must provide npkt if exists)
+ * starting at offset in m compare characters in mbuf chain for 'cmp'
+ * stop at 'max' characters
+ */
+static int
+mbufstrncmp(struct mbuf *m, struct mbuf *npkt, int offset, int len, const char *cmp)
+{
+ struct mbuf *n;
+
+ for (; m != NULL; m = n) {
+ n = npkt;
+ if (npkt)
+ npkt = npkt->m_nextpkt;
+ for (; m; m = m->m_next) {
+ for (; offset < m->m_len; offset++, cmp++, len--) {
+ if (max == 0 || *cmp == '\0')
+ return (1);
+ else if (*cmp != *(mtod(m, char *) + offset))
+ return (0);
+ }
+ if (len == 0 || *cmp == '\0')
+ return (1);
+ offset = 0;
+ }
+ }
+ return (0);
+}
+
+#define STRSETUP(sptr, slen, str) \
+ do { \
+ sptr = str; \
+ slen = sizeof(str) - 1; \
+ } while(0)
+
+static void
+sohashttpget(struct socket *so, void *arg, int waitflag)
+{
+
+ if ((so->so_state & SS_CANTRCVMORE) == 0 && !sbfull(&so->so_rcv)) {
+ struct mbuf *m;
+ const char *cmp;
+ int cmplen, cc;
+
+ m = so->so_rcv.sb_mb;
+ cc = so->so_rcv.sb_cc - 1;
+ if (cc < 1)
+ return;
+ switch (*mtod(m, char *)) {
+ case 'G':
+ STRSETUP(cmp, cmplen, "ET ");
+ break;
+ case 'H':
+ STRSETUP(cmp, cmplen, "EAD ");
+ break;
+ default:
+ goto fallout;
+ }
+ if (cc < cmplen) {
+ if (mbufstrncmp(m, m->m_nextpkt, 1, cc, cmp) == 1) {
+ DPRINT("short cc (%d) but mbufstrncmp ok", cc);
+ return;
+ } else {
+ DPRINT("short cc (%d) mbufstrncmp failed", cc);
+ goto fallout;
+ }
+ }
+ if (mbufstrcmp(m, m->m_nextpkt, 1, cmp) == 1) {
+ DPRINT("mbufstrcmp ok");
+ if (parse_http_version == 0)
+ soishttpconnected(so, arg, waitflag);
+ else
+ soparsehttpvers(so, arg, waitflag);
+ return;
+ }
+ DPRINT("mbufstrcmp bad");
+ }
+
+fallout:
+ DPRINT("fallout");
+ so->so_upcall = NULL;
+ so->so_rcv.sb_flags &= ~SB_UPCALL;
+ soisconnected(so);
+ return;
+}
+
+static void
+soparsehttpvers(struct socket *so, void *arg, int waitflag)
+{
+ struct mbuf *m, *n;
+ int i, cc, spaces, inspaces;
+
+ if ((so->so_state & SS_CANTRCVMORE) != 0 || sbfull(&so->so_rcv))
+ goto fallout;
+
+ m = so->so_rcv.sb_mb;
+ cc = so->so_rcv.sb_cc;
+ inspaces = spaces = 0;
+ for (m = so->so_rcv.sb_mb; m; m = n) {
+ n = m->m_nextpkt;
+ for (; m; m = m->m_next) {
+ for (i = 0; i < m->m_len; i++, cc--) {
+ switch (*(mtod(m, char *) + i)) {
+ case ' ':
+ /* tabs? '\t' */
+ if (!inspaces) {
+ spaces++;
+ inspaces = 1;
+ }
+ break;
+ case '\r':
+ case '\n':
+ DPRINT("newline");
+ goto fallout;
+ default:
+ if (spaces != 2) {
+ inspaces = 0;
+ break;
+ }
+
+ /*
+ * if we don't have enough characters
+ * left (cc < sizeof("HTTP/1.0") - 1)
+ * then see if the remaining ones
+ * are a request we can parse.
+ */
+ if (cc < sizeof("HTTP/1.0") - 1) {
+ if (mbufstrncmp(m, n, i, cc,
+ "HTTP/1.") == 1) {
+ DPRINT("ok");
+ goto readmore;
+ } else {
+ DPRINT("bad");
+ goto fallout;
+ }
+ } else if (
+ mbufstrcmp(m, n, i, "HTTP/1.0") ||
+ mbufstrcmp(m, n, i, "HTTP/1.1")) {
+ DPRINT("ok");
+ soishttpconnected(so,
+ arg, waitflag);
+ return;
+ } else {
+ DPRINT("bad");
+ goto fallout;
+ }
+ }
+ }
+ }
+ }
+readmore:
+ DPRINT("readmore");
+ /*
+ * if we hit here we haven't hit something
+ * we don't understand or a newline, so try again
+ */
+ so->so_upcall = soparsehttpvers;
+ so->so_rcv.sb_flags |= SB_UPCALL;
+ return;
+
+fallout:
+ DPRINT("fallout");
+ so->so_upcall = NULL;
+ so->so_rcv.sb_flags &= ~SB_UPCALL;
+ soisconnected(so);
+ return;
+}
+
+
+#define NCHRS 3
+
+static void
+soishttpconnected(struct socket *so, void *arg, int waitflag)
+{
+ char a, b, c;
+ struct mbuf *m, *n;
+ int ccleft, copied;
+
+ DPRINT("start");
+ if ((so->so_state & SS_CANTRCVMORE) != 0 || sbfull(&so->so_rcv))
+ goto gotit;
+
+ /*
+ * Walk the socketbuffer and copy the last NCHRS (3) into a, b, and c
+ * copied - how much we've copied so far
+ * ccleft - how many bytes remaining in the socketbuffer
+ * just loop over the mbufs subtracting from 'ccleft' until we only
+ * have NCHRS left
+ */
+ copied = 0;
+ ccleft = so->so_rcv.sb_cc;
+ if (ccleft < NCHRS)
+ goto readmore;
+ a = b = c = '\0';
+ for (m = so->so_rcv.sb_mb; m; m = n) {
+ n = m->m_nextpkt;
+ for (; m; m = m->m_next) {
+ ccleft -= m->m_len;
+ if (ccleft <= NCHRS) {
+ char *src;
+ int tocopy;
+
+ tocopy = (NCHRS - ccleft) - copied;
+ src = mtod(m, char *) + (m->m_len - tocopy);
+
+ while (tocopy--) {
+ switch (copied++) {
+ case 0:
+ a = *src++;
+ break;
+ case 1:
+ b = *src++;
+ break;
+ case 2:
+ c = *src++;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (c == '\n' && (b == '\n' || (b == '\r' && a == '\n'))) {
+ /* we have all request headers */
+ goto gotit;
+ }
+
+readmore:
+ so->so_upcall = soishttpconnected;
+ so->so_rcv.sb_flags |= SB_UPCALL;
+ return;
+
+gotit:
+ so->so_upcall = NULL;
+ so->so_rcv.sb_flags &= ~SB_UPCALL;
+ soisconnected(so);
+ return;
+}
--- /workspaces/vendor/nbsrc/sys/sys/socket.h 2008-01-09 14:44:46.000000000 -0500
+++ sys/sys/socket.h 2008-01-28 16:01:36.000000000 -0500
@@ -121,6 +121,7 @@
#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 */


/*
@@ -148,6 +149,11 @@
int l_linger; /* linger time in seconds */
};

+struct accept_filter_arg {
+ char af_name[16];
+ char af_arg[256-16];
+};
+
/*
* Level number for (get/set)sockopt() to apply to socket itself.
*/
--- /workspaces/vendor/nbsrc/sys/sys/socketvar.h 2008-01-09 14:44:46.000000000 -0500
+++ sys/sys/socketvar.h 2008-01-28 16:01:36.000000000 -0500
@@ -134,6 +134,11 @@
struct mbuf **, int *);
struct mowner *so_mowner; /* who owns mbufs for this socket */
struct uidinfo *so_uidinfo; /* who opened the socket */
+ 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;
};

#define SB_EMPTY_FIXUP(sb) \
@@ -254,6 +259,17 @@
} while (/* CONSTCOND */ 0)

#ifdef _KERNEL
+struct accept_filter {
+ char accf_name[16];
+ void (*accf_callback)
+ (struct socket *so, void *arg, int waitflag);
+ void * (*accf_create)
+ (struct socket *so, char *arg);
+ void (*accf_destroy)
+ (struct socket *so);
+ SLIST_ENTRY(accept_filter) accf_next;
+};
+
extern u_long sb_max;
extern int somaxkva;
extern int sock_loan_thresh;
@@ -404,6 +420,21 @@
#define SB_PRIO_OVERDRAFT 2
#define SB_PRIO_BESTEFFORT 3

+/*
+ * Accept filter functions (duh).
+ */
+int do_getopt_accept_filter(struct socket *, struct mbuf *);
+int do_setopt_accept_filter(struct socket *, struct mbuf *);
+int accept_filt_add(struct accept_filter *);
+int accept_filt_del(char *);
+struct accept_filter *accept_filt_get(char *);
+#ifdef ACCEPT_FILTER_MOD
+#ifdef SYSCTL_DECL
+SYSCTL_DECL(_net_inet_accf);
+#endif
+int accept_filt_generic_mod_event(struct lkm_table *lkmtp, int event, void *data);
+#endif
+
#endif /* _KERNEL */

#endif /* !_SYS_SOCKETVAR_H_ */

--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Christos Zoulas
2008-01-29 00:37:25 UTC
Permalink
Post by Thor Lancelot Simon
Post by Thor Lancelot Simon
A coworker has ported the FreeBSD "accept filter" functionality to
NetBSD (approximately 4.99.40 -- I think the attached patch should
apply cleanly to HEAD today, however).
Oops! Here's the patch.
Looks ok; but it has a coyotepoint include... Is there documentation for
it? Also it seems a bit awkward to parse ascii strings in the kernel?


christos
Post by Thor Lancelot Simon
--- /workspaces/vendor/nbsrc/sys/conf/files 2008-01-09 14:44:14.000000000 -0500
+++ sys/conf/files 2008-01-28 16:01:14.000000000 -0500
@@ -1188,6 +1188,9 @@
defpseudo carp: ifnet, ether, arp, bpf_filter
defpseudo etherip { }: ifnet, ether, arp, bpf_filter
+defpseudo accf_data
+defpseudo accf_http
+
defpseudo sequencer
defpseudo clockctl
defpseudo irix_kmem
@@ -1422,6 +1425,7 @@
file kern/tty_ptm.c pty
file kern/tty_subr.c
file kern/tty_tty.c
+file kern/uipc_accf.c inet
file kern/uipc_domain.c
file kern/uipc_mbuf.c
file kern/uipc_mbuf2.c
@@ -1506,6 +1510,8 @@
file netinet/ip_etherip.c etherip & inet
file netinet6/ip6_etherip.c etherip & inet6
file netinet6/in6_gif.c gif & inet6
+file netinet/accf_data.c inet & accf_data
+file netinet/accf_http.c inet & accf_http
file netisdn/i4b_ctl.c isdnctl needs-flag
file netisdn/i4b_isppp.c ippp needs-count
@@ -1559,3 +1565,6 @@
# Pseudo audio device
#
include "dev/pad/files.pad"
+# Coyote Point Equalizer
+#
+include "l7lb/files.EQ"
--- /dev/null 2008-01-28 15:53:44.000000000 -0500
+++ sys/kern/uipc_accf.c 2008-01-28 16:01:30.000000000 -0500
@@ -0,0 +1,301 @@
+/*-
+ * Copyright (c) 2000 Paycounter, Inc.
+ * Copyright (c) 2005 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: uipc_accf.c $");
+
+#define ACCEPT_FILTER_MOD
+
+#include "opt_inet.h"
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/domain.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/lkm.h>
+#include <sys/mutex.h>
+#include <sys/protosw.h>
+#include <sys/sysctl.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");
+
+static int unloadable = 0;
+
+/*
+ * Names of Accept filter sysctl objects
+ */
+
+#define ACCFCTL_UNLOADABLE 1 /* Allow module to be unloaded */
+
+
+SYSCTL_SETUP(sysctl_net_inet_accf_setup, "sysctl net.inet.accf subtree setup")
+{
+ sysctl_createv(clog, 0, NULL, NULL,
+ CTLFLAG_PERMANENT,
+ CTLTYPE_NODE, "net", NULL,
+ NULL, 0, NULL, 0,
+ CTL_NET, CTL_EOL);
+ sysctl_createv(clog, 0, NULL, NULL,
+ CTLFLAG_PERMANENT,
+ CTLTYPE_NODE, "inet", NULL,
+ NULL, 0, NULL, 0,
+ CTL_NET, PF_INET, CTL_EOL);
+ sysctl_createv(clog, 0, NULL, NULL,
+ CTLFLAG_PERMANENT,
+ CTLTYPE_NODE, "accf",
+ SYSCTL_DESCR("Accept filters"),
+ NULL, 0, NULL, 0,
+ CTL_NET, PF_INET, SO_ACCEPTFILTER, CTL_EOL);
+ sysctl_createv(clog, 0, NULL, NULL,
+ CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+ CTLTYPE_INT, "unloadable",
+ SYSCTL_DESCR("Allow unload of accept filters "
+ "(not recommended)"),
+ NULL, 0, &unloadable, 0,
+ CTL_NET, PF_INET, SO_ACCEPTFILTER,
+ ACCFCTL_UNLOADABLE, CTL_EOL);
+}
+
+/*
+ * 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)
+ break;
+
+ return (p);
+}
+
+int
+accept_filt_generic_mod_event(struct lkm_table *lkmtp, int event, void *data)
+{
+ struct accept_filter *p;
+ struct accept_filter *accfp = (struct accept_filter *) data;
+ int error;
+
+ switch (event) {
+ MALLOC(p, struct accept_filter *, sizeof(*p), M_ACCF,
+ M_WAITOK);
+ bcopy(accfp, p, sizeof(*p));
+ error = accept_filt_add(p);
+ break;
+
+ /*
+ * Do not support unloading yet. we don't keep track of
+ * refcounts and unloading an accept filter callback and then
+ * having it called is a bad thing. A simple fix would be to
+ * track the refcount in the struct accept_filter.
+ */
+ if (unloadable != 0) {
+ error = accept_filt_del(accfp->accf_name);
+ } else
+ error = EOPNOTSUPP;
+ break;
+
+ error = 0;
+ break;
+
+ error = EOPNOTSUPP;
+ break;
+ }
+
+ return (error);
+}
+
+int
+do_getopt_accept_filter(struct socket *so, struct mbuf *m)
+{
+ int error;
+
+ error = 0;
+ if ((so->so_options & SO_ACCEPTCONN) == 0) {
+ error = EINVAL;
+ goto out;
+ }
+ if ((so->so_options & SO_ACCEPTFILTER) == 0) {
+ error = EINVAL;
+ goto out;
+ }
+ m->m_len = sizeof(struct accept_filter_arg);
+ strcpy(mtod(m, struct accept_filter_arg *)->af_name,
so->so_accf->so_accept_filter->accf_name);
+ if (so->so_accf->so_accept_filter_str != NULL)
+ strcpy(mtod(m, struct accept_filter_arg *)->af_arg,
so->so_accf->so_accept_filter_str);
+ return (error);
+}
+
+int
+do_setopt_accept_filter(struct socket *so, struct mbuf *m)
+{
+ struct accept_filter_arg *afap;
+ struct accept_filter *afp;
+ struct so_accf *newaf;
+ int error = 0;
+
+ /*
+ * Handle the simple delete case first.
+ */
+ if (m == NULL || mtod(m, struct accept_filter_arg *) == NULL) {
+ if ((so->so_options & SO_ACCEPTCONN) == 0) {
+ return (EINVAL);
+ }
+ if (so->so_accf != NULL) {
+ struct so_accf *af = so->so_accf;
+ 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);
+ }
+
+ /*
+ * Pre-allocate any memory we may need later to avoid blocking at
+ * untimely moments. This does not optimize for invalid arguments.
+ */
+ if (m->m_len != sizeof(struct accept_filter_arg)) {
+ return (EINVAL);
+ }
+ afap = mtod(m, struct accept_filter_arg *);
+ afap->af_name[sizeof(afap->af_name)-1] = '\0';
+ afap->af_arg[sizeof(afap->af_arg)-1] = '\0';
+ if (error) {
+ return (error);
+ }
+ afp = accept_filt_get(afap->af_name);
+ if (afp == NULL) {
+ return (ENOENT);
+ }
+ /*
+ * Allocate the new accept filter instance storage. We may
+ * have to free it again later if we fail to attach it. If
+ * attached properly, 'newaf' is NULLed to avoid a free()
+ * while in use.
+ */
+ MALLOC(newaf, struct so_accf *, sizeof(*newaf), M_ACCF, M_WAITOK |
+ M_ZERO);
+ if (afp->accf_create != NULL && afap->af_name[0] != '\0') {
+ int len = strlen(afap->af_name) + 1;
+ MALLOC(newaf->so_accept_filter_str, char *, len, M_ACCF,
+ M_WAITOK);
+ strcpy(newaf->so_accept_filter_str, afap->af_name);
+ }
+
+ /*
+ * Require a listen socket; don't try to replace an existing filter
+ * without first removing it.
+ */
+ if (((so->so_options & SO_ACCEPTCONN) == 0) ||
+ (so->so_accf != NULL)) {
+ error = EINVAL;
+ goto out;
+ }
+
+ /*
+ * Invoke the accf_create() method of the filter if required. The
+ * socket mutex is held over this call, so create methods for filters
+ * can't block.
+ */
+ if (afp->accf_create != NULL) {
+ newaf->so_accept_filter_arg =
+ afp->accf_create(so, afap->af_arg);
+ if (newaf->so_accept_filter_arg == NULL) {
+ error = EINVAL;
+ goto out;
+ }
+ }
+ newaf->so_accept_filter = afp;
+ so->so_accf = newaf;
+ so->so_options |= SO_ACCEPTFILTER;
+ newaf = NULL;
+ if (newaf != NULL) {
+ if (newaf->so_accept_filter_str != NULL)
+ FREE(newaf->so_accept_filter_str, M_ACCF);
+ FREE(newaf, M_ACCF);
+ }
+ return (error);
+}
--- /workspaces/vendor/nbsrc/sys/kern/uipc_socket.c 2008-01-09
14:44:39.000000000 -0500
+++ sys/kern/uipc_socket.c 2008-01-28 16:01:30.000000000 -0500
@@ -70,6 +70,7 @@
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uipc_socket.c,v 1.149 2007/12/05 17:19:59 pooka Exp $");
+#include "opt_inet.h"
#include "opt_sock_counters.h"
#include "opt_sosend_loan.h"
#include "opt_mbuftrace.h"
@@ -625,6 +626,11 @@
sorflush(so);
seldestroy(&so->so_rcv.sb_sel);
seldestroy(&so->so_snd.sb_sel);
+#ifdef INET
+ /* remove acccept filter if one is present. */
+ if (so->so_accf != NULL)
+ do_setopt_accept_filter(so, NULL);
+#endif
pool_put(&socket_pool, so);
}
@@ -1460,13 +1466,25 @@
static int
sosetopt1(struct socket *so, int level, int optname, struct mbuf *m)
{
+#ifdef INET
+ int error, optval, val;
+#else
int optval, val;
+#endif
struct linger *l;
struct sockbuf *sb;
struct timeval *tv;
switch (optname) {
+#ifdef INET
+ error = do_setopt_accept_filter(so, m);
+ if (error)
+ return error;
+ break;
+#endif
+
if (m == NULL || m->m_len != sizeof(struct linger))
return EINVAL;
@@ -1596,6 +1614,9 @@
int
sogetopt(struct socket *so, int level, int optname, struct mbuf **mp)
{
+#ifdef INET
+ int error;
+#endif
struct mbuf *m;
if (level != SOL_SOCKET) {
@@ -1610,6 +1631,14 @@
switch (optname) {
+#ifdef INET
+ error = do_getopt_accept_filter(so, m);
+ if (error)
+ return error;
+ break;
+#endif
+
m->m_len = sizeof(struct linger);
mtod(m, struct linger *)->l_onoff =
--- /workspaces/vendor/nbsrc/sys/kern/uipc_socket2.c 2008-01-09
14:44:39.000000000 -0500
+++ sys/kern/uipc_socket2.c 2008-01-28 16:01:30.000000000 -0500
@@ -34,6 +34,7 @@
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uipc_socket2.c,v 1.86 2007/09/25 14:04:07 ad Exp $");
+#include "opt_inet.h"
#include "opt_mbuftrace.h"
#include "opt_sb_max.h"
@@ -110,10 +111,20 @@
head = so->so_head;
so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING|SS_ISCONFIRMING);
so->so_state |= SS_ISCONNECTED;
- if (head && soqremque(so, 0)) {
- soqinsque(head, so, 1);
- sorwakeup(head);
- wakeup((void *)&head->so_timeo);
+ if (head && so->so_onq == &head->so_q0) {
+ if ((so->so_options & SO_ACCEPTFILTER) == 0) {
+ soqremque(so, 0);
+ soqinsque(head, so, 1);
+ sorwakeup(head);
+ wakeup((void *)&head->so_timeo);
+ } else {
+ 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;
+ so->so_upcall(so, so->so_upcallarg, M_DONTWAIT);
+ }
} else {
wakeup((void *)&so->so_timeo);
sorwakeup(so);
@@ -157,6 +168,8 @@
struct socket *so;
int soqueue;
+ if ((head->so_options & SO_ACCEPTFILTER) != 0)
+ connstatus = 0;
soqueue = connstatus ? 1 : 0;
if (head->so_qlen + head->so_q0len > 3 * head->so_qlimit / 2)
return ((struct socket *)0);
@@ -195,6 +208,11 @@
(void) soqremque(so, soqueue);
seldestroy(&so->so_rcv.sb_sel);
seldestroy(&so->so_snd.sb_sel);
+#ifdef INET
+ /* remove acccept filter if one is present. */
+ if (so->so_accf != NULL)
+ do_setopt_accept_filter(so, NULL);
+#endif
pool_put(&socket_pool, so);
return (NULL);
}
--- /dev/null 2008-01-28 15:53:44.000000000 -0500
+++ sys/netinet/accept_filter.h 2008-01-28 16:01:33.000000000 -0500
@@ -0,0 +1,50 @@
+/* $NetBSD: accept_filter.h $ */
+
+/*
+ * Copyright (c) 2006 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Rui Paulo.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#ifndef _NETINET_ACCEPT_FILTER_H
+#define _NETINET_ACCEPT_FILTER_H
+
+/*
+ * Valid accept filter list
+ * Currently it is used for creting sysctl object
+ */
+
+#define ACCF_DATA 1 /* Data ready accept filter */
+#define ACCF_HTTP 2 /* HTTP ready accept filter */
+
+#endif /* _NETINET_ACCEPT_FILTER_H */
--- /dev/null 2008-01-28 15:53:44.000000000 -0500
+++ sys/netinet/accf_data.c 2008-01-28 16:01:33.000000000 -0500
@@ -0,0 +1,93 @@
+/*-
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: accf_data.c $");
+
+#define ACCEPT_FILTER_MOD
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/lkm.h>
+#include <sys/sysctl.h>
+#include <sys/signalvar.h>
+#include <sys/socketvar.h>
+#include <netinet/accept_filter.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,
+ {NULL,}
+};
+
+void accf_dataattach(int);
+void accf_dataattach(int num)
+{
+ accept_filt_generic_mod_event(NULL, LKM_E_LOAD, &accf_data_filter);
+}
+
+#ifdef _LKM
+static int accf_data_handle(struct lkm_table * lkmtp, int cmd);
+int accf_data_lkmentry(struct lkm_table * lkmtp, int cmd, int ver);
+
+MOD_MISC("accf_data");
+
+static int accf_data_handle(struct lkm_table * lkmtp, int cmd)
+{
+
+ printf("called this funtion\n");
+ return accept_filt_generic_mod_event(lkmtp, cmd, &accf_data_filter);
+}
+
+/*
+ * the module entry point.
+ */
+int
+accf_data_lkmentry(struct lkm_table *lkmtp, int cmd, int ver)
+{
+ DISPATCH(lkmtp, cmd, ver, accf_data_handle, accf_data_handle,
+ accf_data_handle)
+}
+#endif
+
+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;
+}
--- /dev/null 2008-01-28 15:53:44.000000000 -0500
+++ sys/netinet/accf_http.c 2008-01-28 16:01:33.000000000 -0500
@@ -0,0 +1,421 @@
+/*-
+ * Copyright (c) 2000 Paycounter, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: accf_data.c $");
+
+#define ACCEPT_FILTER_MOD
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/lkm.h>
+#include <sys/signalvar.h>
+#include <sys/sysctl.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <netinet/accept_filter.h>
+
+/* check for GET/HEAD */
+static void sohashttpget(struct socket *so, void *arg, int waitflag);
+/* check for HTTP/1.0 or HTTP/1.1 */
+static void soparsehttpvers(struct socket *so, void *arg, int waitflag);
+/* check for end of HTTP/1.x request */
+static void soishttpconnected(struct socket *so, void *arg, int waitflag);
+/* strcmp on an mbuf chain */
+static int mbufstrcmp(struct mbuf *m, struct mbuf *npkt, int offset, const char *cmp);
+/* strncmp on an mbuf chain */
+static int mbufstrncmp(struct mbuf *m, struct mbuf *npkt, int offset,
+ int len, const char *cmp);
+/* socketbuffer is full */
+static int sbfull(struct sockbuf *sb);
+
+static struct accept_filter accf_http_filter = {
+ "httpready",
+ sohashttpget,
+ NULL,
+ NULL,
+ {NULL,}
+};
+
+/*
+ * Names of HTTP Accept filter sysctl objects
+ */
+
+#define ACCFCTL_PARSEVER 1 /* Parse HTTP version */
+
+static int parse_http_version = 1;
+
+SYSCTL_SETUP(sysctl_net_inet_accf__http_setup, "sysctl
net.inet.accf.http subtree setup")
+{
+ sysctl_createv(clog, 0, NULL, NULL,
+ CTLFLAG_PERMANENT,
+ CTLTYPE_NODE, "net", NULL,
+ NULL, 0, NULL, 0,
+ CTL_NET, CTL_EOL);
+ sysctl_createv(clog, 0, NULL, NULL,
+ CTLFLAG_PERMANENT,
+ CTLTYPE_NODE, "inet", NULL,
+ NULL, 0, NULL, 0,
+ CTL_NET, PF_INET, CTL_EOL);
+ sysctl_createv(clog, 0, NULL, NULL,
+ CTLFLAG_PERMANENT,
+ CTLTYPE_NODE, "accf", NULL,
+ NULL, 0, NULL, 0,
+ CTL_NET, PF_INET, SO_ACCEPTFILTER, CTL_EOL);
+ sysctl_createv(clog, 0, NULL, NULL,
+ CTLFLAG_PERMANENT,
+ CTLTYPE_NODE, "http",
+ SYSCTL_DESCR("HTTP accept filter"),
+ NULL, 0, NULL, 0,
+ CTL_NET, PF_INET, SO_ACCEPTFILTER, ACCF_HTTP, CTL_EOL);
+ sysctl_createv(clog, 0, NULL, NULL,
+ CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+ CTLTYPE_INT, "parsehttpversion",
+ SYSCTL_DESCR("Parse http version so that non "
+ "1.x requests work"),
+ NULL, 0, &parse_http_version, 0,
+ CTL_NET, PF_INET, SO_ACCEPTFILTER, ACCF_HTTP,
+ ACCFCTL_PARSEVER, CTL_EOL);
+}
+
+void accf_httpattach(int);
+void accf_httpattach(int num)
+{
+ accept_filt_generic_mod_event(NULL, LKM_E_LOAD, &accf_http_filter);
+}
+
+#ifdef _LKM
+static int accf_http_handle(struct lkm_table * lkmtp, int cmd);
+int accf_http_lkmentry(struct lkm_table * lkmtp, int cmd, int ver);
+
+MOD_MISC("accf_http");
+
+static int accf_http_handle(struct lkm_table * lkmtp, int cmd)
+{
+
+ return accept_filt_generic_mod_event(lkmtp, cmd, &accf_http_filter);
+}
+
+/*
+ * the module entry point.
+ */
+int
+accf_http_lkmentry(struct lkm_table *lkmtp, int cmd, int ver)
+{
+ DISPATCH(lkmtp, cmd, ver, accf_http_handle, accf_http_handle,
+ accf_http_handle)
+}
+#endif
+
+
+
+#ifdef ACCF_HTTP_DEBUG
+#define DPRINT(fmt, args...) \
+ do { \
+ printf("%s:%d: " fmt "\n", __func__, __LINE__, ##args); \
+ } while (0)
+#else
+#define DPRINT(fmt, args...)
+#endif
+
+static int
+sbfull(struct sockbuf *sb)
+{
+
+ DPRINT("sbfull, cc(%ld) >= hiwat(%ld): %d, "
+ "mbcnt(%ld) >= mbmax(%ld): %d",
+ sb->sb_cc, sb->sb_hiwat, sb->sb_cc >= sb->sb_hiwat,
+ sb->sb_mbcnt, sb->sb_mbmax, sb->sb_mbcnt >= sb->sb_mbmax);
+ return (sb->sb_cc >= sb->sb_hiwat || sb->sb_mbcnt >= sb->sb_mbmax);
+}
+
+/*
+ * start at mbuf m, (must provide npkt if exists)
+ * starting at offset in m compare characters in mbuf chain for 'cmp'
+ */
+static int
+mbufstrcmp(struct mbuf *m, struct mbuf *npkt, int offset, const char *cmp)
+{
+ struct mbuf *n;
+
+ for (; m != NULL; m = n) {
+ n = npkt;
+ if (npkt)
+ npkt = npkt->m_nextpkt;
+ for (; m; m = m->m_next) {
+ for (; offset < m->m_len; offset++, cmp++) {
+ if (*cmp == '\0')
+ return (1);
+ else if (*cmp != *(mtod(m, char *) + offset))
+ return (0);
+ }
+ if (*cmp == '\0')
+ return (1);
+ offset = 0;
+ }
+ }
+ return (0);
+}
+
+/*
+ * start at mbuf m, (must provide npkt if exists)
+ * starting at offset in m compare characters in mbuf chain for 'cmp'
+ * stop at 'max' characters
+ */
+static int
+mbufstrncmp(struct mbuf *m, struct mbuf *npkt, int offset, int len, const char *cmp)
+{
+ struct mbuf *n;
+
+ for (; m != NULL; m = n) {
+ n = npkt;
+ if (npkt)
+ npkt = npkt->m_nextpkt;
+ for (; m; m = m->m_next) {
+ for (; offset < m->m_len; offset++, cmp++, len--) {
+ if (max == 0 || *cmp == '\0')
+ return (1);
+ else if (*cmp != *(mtod(m, char *) + offset))
+ return (0);
+ }
+ if (len == 0 || *cmp == '\0')
+ return (1);
+ offset = 0;
+ }
+ }
+ return (0);
+}
+
+#define STRSETUP(sptr, slen, str) \
+ do { \
+ sptr = str; \
+ slen = sizeof(str) - 1; \
+ } while(0)
+
+static void
+sohashttpget(struct socket *so, void *arg, int waitflag)
+{
+
+ if ((so->so_state & SS_CANTRCVMORE) == 0 && !sbfull(&so->so_rcv)) {
+ struct mbuf *m;
+ const char *cmp;
+ int cmplen, cc;
+
+ m = so->so_rcv.sb_mb;
+ cc = so->so_rcv.sb_cc - 1;
+ if (cc < 1)
+ return;
+ switch (*mtod(m, char *)) {
+ STRSETUP(cmp, cmplen, "ET ");
+ break;
+ STRSETUP(cmp, cmplen, "EAD ");
+ break;
+ goto fallout;
+ }
+ if (cc < cmplen) {
+ if (mbufstrncmp(m, m->m_nextpkt, 1, cc, cmp) == 1) {
+ DPRINT("short cc (%d) but mbufstrncmp ok", cc);
+ return;
+ } else {
+ DPRINT("short cc (%d) mbufstrncmp failed", cc);
+ goto fallout;
+ }
+ }
+ if (mbufstrcmp(m, m->m_nextpkt, 1, cmp) == 1) {
+ DPRINT("mbufstrcmp ok");
+ if (parse_http_version == 0)
+ soishttpconnected(so, arg, waitflag);
+ else
+ soparsehttpvers(so, arg, waitflag);
+ return;
+ }
+ DPRINT("mbufstrcmp bad");
+ }
+
+ DPRINT("fallout");
+ so->so_upcall = NULL;
+ so->so_rcv.sb_flags &= ~SB_UPCALL;
+ soisconnected(so);
+ return;
+}
+
+static void
+soparsehttpvers(struct socket *so, void *arg, int waitflag)
+{
+ struct mbuf *m, *n;
+ int i, cc, spaces, inspaces;
+
+ if ((so->so_state & SS_CANTRCVMORE) != 0 || sbfull(&so->so_rcv))
+ goto fallout;
+
+ m = so->so_rcv.sb_mb;
+ cc = so->so_rcv.sb_cc;
+ inspaces = spaces = 0;
+ for (m = so->so_rcv.sb_mb; m; m = n) {
+ n = m->m_nextpkt;
+ for (; m; m = m->m_next) {
+ for (i = 0; i < m->m_len; i++, cc--) {
+ switch (*(mtod(m, char *) + i)) {
+ /* tabs? '\t' */
+ if (!inspaces) {
+ spaces++;
+ inspaces = 1;
+ }
+ break;
+ DPRINT("newline");
+ goto fallout;
+ if (spaces != 2) {
+ inspaces = 0;
+ break;
+ }
+
+ /*
+ * if we don't have enough characters
+ * left (cc < sizeof("HTTP/1.0") - 1)
+ * then see if the remaining ones
+ * are a request we can parse.
+ */
+ if (cc < sizeof("HTTP/1.0") - 1) {
+ if (mbufstrncmp(m, n, i, cc,
+ "HTTP/1.") == 1) {
+ DPRINT("ok");
+ goto readmore;
+ } else {
+ DPRINT("bad");
+ goto fallout;
+ }
+ } else if (
+ mbufstrcmp(m, n, i, "HTTP/1.0") ||
+ mbufstrcmp(m, n, i, "HTTP/1.1")) {
+ DPRINT("ok");
+ soishttpconnected(so,
+ arg, waitflag);
+ return;
+ } else {
+ DPRINT("bad");
+ goto fallout;
+ }
+ }
+ }
+ }
+ }
+ DPRINT("readmore");
+ /*
+ * if we hit here we haven't hit something
+ * we don't understand or a newline, so try again
+ */
+ so->so_upcall = soparsehttpvers;
+ so->so_rcv.sb_flags |= SB_UPCALL;
+ return;
+
+ DPRINT("fallout");
+ so->so_upcall = NULL;
+ so->so_rcv.sb_flags &= ~SB_UPCALL;
+ soisconnected(so);
+ return;
+}
+
+
+#define NCHRS 3
+
+static void
+soishttpconnected(struct socket *so, void *arg, int waitflag)
+{
+ char a, b, c;
+ struct mbuf *m, *n;
+ int ccleft, copied;
+
+ DPRINT("start");
+ if ((so->so_state & SS_CANTRCVMORE) != 0 || sbfull(&so->so_rcv))
+ goto gotit;
+
+ /*
+ * Walk the socketbuffer and copy the last NCHRS (3) into a, b, and c
+ * copied - how much we've copied so far
+ * ccleft - how many bytes remaining in the socketbuffer
+ * just loop over the mbufs subtracting from 'ccleft' until we only
+ * have NCHRS left
+ */
+ copied = 0;
+ ccleft = so->so_rcv.sb_cc;
+ if (ccleft < NCHRS)
+ goto readmore;
+ a = b = c = '\0';
+ for (m = so->so_rcv.sb_mb; m; m = n) {
+ n = m->m_nextpkt;
+ for (; m; m = m->m_next) {
+ ccleft -= m->m_len;
+ if (ccleft <= NCHRS) {
+ char *src;
+ int tocopy;
+
+ tocopy = (NCHRS - ccleft) - copied;
+ src = mtod(m, char *) + (m->m_len - tocopy);
+
+ while (tocopy--) {
+ switch (copied++) {
+ a = *src++;
+ break;
+ b = *src++;
+ break;
+ c = *src++;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (c == '\n' && (b == '\n' || (b == '\r' && a == '\n'))) {
+ /* we have all request headers */
+ goto gotit;
+ }
+
+ so->so_upcall = soishttpconnected;
+ so->so_rcv.sb_flags |= SB_UPCALL;
+ return;
+
+ so->so_upcall = NULL;
+ so->so_rcv.sb_flags &= ~SB_UPCALL;
+ soisconnected(so);
+ return;
+}
--- /workspaces/vendor/nbsrc/sys/sys/socket.h 2008-01-09
14:44:46.000000000 -0500
+++ sys/sys/socket.h 2008-01-28 16:01:36.000000000 -0500
@@ -121,6 +121,7 @@
#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 */
/*
@@ -148,6 +149,11 @@
int l_linger; /* linger time in seconds */
};
+struct accept_filter_arg {
+ char af_name[16];
+ char af_arg[256-16];
+};
+
/*
* Level number for (get/set)sockopt() to apply to socket itself.
*/
--- /workspaces/vendor/nbsrc/sys/sys/socketvar.h 2008-01-09
14:44:46.000000000 -0500
+++ sys/sys/socketvar.h 2008-01-28 16:01:36.000000000 -0500
@@ -134,6 +134,11 @@
struct mbuf **, int *);
struct mowner *so_mowner; /* who owns mbufs for this socket */
struct uidinfo *so_uidinfo; /* who opened the socket */
+ 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;
};
#define SB_EMPTY_FIXUP(sb) \
@@ -254,6 +259,17 @@
} while (/* CONSTCOND */ 0)
#ifdef _KERNEL
+struct accept_filter {
+ char accf_name[16];
+ void (*accf_callback)
+ (struct socket *so, void *arg, int waitflag);
+ void * (*accf_create)
+ (struct socket *so, char *arg);
+ void (*accf_destroy)
+ (struct socket *so);
+ SLIST_ENTRY(accept_filter) accf_next;
+};
+
extern u_long sb_max;
extern int somaxkva;
extern int sock_loan_thresh;
@@ -404,6 +420,21 @@
#define SB_PRIO_OVERDRAFT 2
#define SB_PRIO_BESTEFFORT 3
+/*
+ * Accept filter functions (duh).
+ */
+int do_getopt_accept_filter(struct socket *, struct mbuf *);
+int do_setopt_accept_filter(struct socket *, struct mbuf *);
+int accept_filt_add(struct accept_filter *);
+int accept_filt_del(char *);
+struct accept_filter *accept_filt_get(char *);
+#ifdef ACCEPT_FILTER_MOD
+#ifdef SYSCTL_DECL
+SYSCTL_DECL(_net_inet_accf);
+#endif
+int accept_filt_generic_mod_event(struct lkm_table *lkmtp, int event, void *data);
+#endif
+
#endif /* _KERNEL */
#endif /* !_SYS_SOCKETVAR_H_ */
--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Thor Lancelot Simon
2008-01-29 05:13:54 UTC
Permalink
Post by Christos Zoulas
Looks ok; but it has a coyotepoint include... Is there documentation for
it? Also it seems a bit awkward to parse ascii strings in the kernel?
Whoops. That include is not necessary. Do you see a way to retain
compatibility with the FreeBSD API, allow the addition of further
filter modules without forcing the recompilation of existing applications,
and not parse the ASCII string in the kernel? If so, I'll make the
appropriate adjustment.

I have a half-cooked patch for inetd to all specification of an accept
filter and its argument after the socket type, if the socket type is
"stream":

http stream:http,argument tcp .....

I'll post it when I get a chance to test whether it works as I expect.
FreeBSD has accept_filter(9) and accf_httpd(9) and accf_dataready(9).
I will produce an accf_ssl(9) as well, sooner or later, which waits
to receive a minimum-size SSL record before bothering userspace. Filters
for common protocols are pretty easy to write and another one it would be
neat to have would be SMTP.

Thor

--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Christos Zoulas
2008-01-29 17:35:49 UTC
Permalink
On Jan 29, 12:13am, ***@rek.tjls.com (Thor Lancelot Simon) wrote:
-- Subject: Re: Patch: accept filters for NetBSD

| On Tue, Jan 29, 2008 at 12:37:25AM +0000, Christos Zoulas wrote:
| >
| > Looks ok; but it has a coyotepoint include... Is there documentation for
| > it? Also it seems a bit awkward to parse ascii strings in the kernel?
|
| Whoops. That include is not necessary. Do you see a way to retain
| compatibility with the FreeBSD API, allow the addition of further
| filter modules without forcing the recompilation of existing applications,
| and not parse the ASCII string in the kernel? If so, I'll make the
| appropriate adjustment.

I don't see a way, seeing that we have a precedence of using PLISTs, perhaps
we should not be compatible and use PLISTS [if appropriate] like we do in
other ioctls.

| I have a half-cooked patch for inetd to all specification of an accept
| filter and its argument after the socket type, if the socket type is
| "stream":
|
| http stream:http,argument tcp .....
|
| I'll post it when I get a chance to test whether it works as I expect.
| FreeBSD has accept_filter(9) and accf_httpd(9) and accf_dataready(9).
| I will produce an accf_ssl(9) as well, sooner or later, which waits
| to receive a minimum-size SSL record before bothering userspace. Filters
| for common protocols are pretty easy to write and another one it would be
| neat to have would be SMTP.

Sounds good to me.

christos

--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Darren Reed
2008-01-29 09:15:42 UTC
Permalink
Hmmm..

Are you going to contribute (or suggest) changes to the FreeBSD
code based on any changes we might make?

For example, is it worth creating mbuf_string.c in kern/ and
putting mbuf_str*cmp() in there? I'm sure I can see there being
a need for mbuf_strcase*cmp() if this is extended further...etc.

Looking at soishttpconnected(), it would seem the algorithm used
there could be better replaced with a call to a function to get
the total data buffered and then doing copydata() with the offset
being "n-3", etc.

...but none of this is worthwhile if it only lives in our tree.

Darren

--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Iain Hibbert
2008-01-29 09:19:45 UTC
Permalink
Post by Thor Lancelot Simon
A coworker has ported the FreeBSD "accept filter" functionality to
NetBSD (approximately 4.99.40 -- I think the attached patch should
apply cleanly to HEAD today, however). Accept filters are kernel
level filters, enabled with setsockopt(), which can perform arbitrary
operations on a TCP or local stream connection before accept() returns
to userspace or the listen socket selects ready for accept. Think of
it as a much more sophisticated version of the socket watermark.
I think I like this idea (have not studied it in detail) except that

+#ifdef INET
+ case SO_ACCEPTFILTER:
+ error = do_setopt_accept_filter(so, m);
+ if (error)
+ return error;
+ break;
+#endif

I'm not sure why its for INET only?

does the filter apply to the socket that it is optioned from or for all
sockets?

There is a case in the bluetooth land to be able to limit connections to a
specific remote device address. This is possible inside the kernel as a
protocol callback indicates if it wants to accept or not but it would be
interesting to be able to do this from userland, if this mechanism was
generic enough.

iain

--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Elad Efrat
2008-01-29 10:36:27 UTC
Permalink
Post by Christos Zoulas
Post by Thor Lancelot Simon
Post by Thor Lancelot Simon
A coworker has ported the FreeBSD "accept filter" functionality to
NetBSD (approximately 4.99.40 -- I think the attached patch should
apply cleanly to HEAD today, however).
Oops! Here's the patch.
Looks ok; but it has a coyotepoint include... Is there documentation for
it? Also it seems a bit awkward to parse ascii strings in the kernel?
Yes, very, but the point is to save the context switches IIUC.

I'm sorry, but this whole thing looks very dodgy to me. :/ There's just
something disturbing about putting string parsing in the kernel network
stack.

What's the motivation of adding the accept filters? I understand one may
be performance -- are there any relevant benchmarks? Is it possible to
hear more about why this is necessary, and what are planned future
extensions, if any?

FWIW, a quick search didn't come up with any benchmarks nor discussions
in the FreeBSD archives. Maybe it was too quick? :)

Also, (as joerg@ pointed out?) what's the reason for putting code in
netinet?

Thanks,

-e.

--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Joerg Sonnenberger
2008-01-29 10:41:06 UTC
Permalink
Post by Elad Efrat
What's the motivation of adding the accept filters? I understand one may
be performance -- are there any relevant benchmarks? Is it possible to
hear more about why this is necessary, and what are planned future
extensions, if any?
The motivation for accept filters is to not have to worry about
connections until a certain amount of data was send. This helps reducing
the load on the server.

Joerg

--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Thor Lancelot Simon
2008-01-29 17:40:31 UTC
Permalink
(1) a socketopt to turn on/off "dataready" behaviour
(2) a socketopt to set a "banner" string, output to each new connection
by the kernel on accept, followed by waiting for an input packet
if dataready is turned on
Incompatible with freebsd, slighly less versatile. Simple & elegant - or
evil hack?
You may very well want to make some connections go away without ever
bothering userspace. That almost always requires looking at the data.
Consider SMTP -- these days you might want to hang up the phone on
someone who doesn't HELO (or EHLO) you. Or "HTTP" peers who don't send
you a GET or POST.

Or consider a protocol that is record-oriented but runs over TCP. The
records may be large, and may arrive in multiple TCP packets (you would
not believe the kind of pathological peer behavior I've seen in this
regard, including an HTTP peer who sent exactly one byte per packet).
Just waiting for one packet won't do: you have to peek into
the first one to get the record length, and then bother userspace after
you've got the whole thing.
--
Thor Lancelot Simon ***@rek.tjls.com

"The inconsistency is startling, though admittedly, if consistency is to
be abandoned or transcended, there is no problem." - Noam Chomsky

--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Elad Efrat
2008-01-29 18:19:29 UTC
Permalink
Post by Elad Efrat
I'm sorry, but this whole thing looks very dodgy to me. :/ There's just
something disturbing about putting string parsing in the kernel network
stack.
Well, you don't have to use it; it is a per-socket option, after all.
Obviously I don't, but others do, and I'm merely raising a general
concern saying "let's give this a bit more though" given my -- and I
presume others' -- experience with fun things that can happen due to
improper string handling and/or bugs in privileged code paths. ;)
Post by Elad Efrat
What's the motivation of adding the accept filters? I understand one may
be performance -- are there any relevant benchmarks? Is it possible to
hear more about why this is necessary, and what are planned future
extensions, if any?
It is not necessary. It provides an opportunity to optimize the processing
of certain application-layer protocols (the ones that like to make a lot
of connections at once)
I'm afraid I don't agree benchmarks are unnecessary. You are introducing
code to the kernel's networking stack, specifically one that will be
used by high profile services. In the OpenSSH world, a bug in the code
you are adding would be considered a pre-auth bug. These are not fun in
services, much less in the kernel.

All I ask for is information about the pros and cons of this feature, to
allow others make the trade off they want based on real data.
without moving the entire protocol into the kernel,
which you would presumably object to much more (talk about string parsing
in the kernel! :-)).
That's where I'm afraid we'll end up. :)
This is one of those features that has been in FreeBSD for about a decade
but was just never noticed by us over here on the NetBSD side of the fence.
Apache and a few other things can use it, but most of the code that uses
it heavily probably is proprietary code belonging to device vendors -- I
know mine is.
I've only seen mentions about Apache. Honestly, it seems this feature
was pushed by Yahoo! who used FreeBSD Apache servers in 2000. Are we
sure today's reality matches that of ~8 years ago?

Again, the best way to make it clear what this feature provides are
benchmarks, as this is what it aims to provide...
I think it is better for NetBSD to not diverge from FreeBSD in this sort
of area if we can arrange not to.
"It is a duplicative and bogus API and I am glad it
is not present in NetBSD, where we provide a way to get the
same or better performance characteristics without requiring
use of a nonstandard and ill-conceived extension."

In a thread starting at:

http://mail-index.netbsd.org/netbsd-users/2007/02/27/0012.html

;)

More seriously, though, I would appreciate if you could not only say
adding this optimizes something, but actually show it does.
I don't have any benchmarks immediately available that I can release but
I'm adding support for this to inetd, which should provide a useful
demonstration and an opportunity to get some quick numbers. I hope that's
helpful.
Is inetd the "intended" use for this feature? (see above about Apache)
Post by Elad Efrat
FWIW, a quick search didn't come up with any benchmarks nor discussions
in the FreeBSD archives. Maybe it was too quick? :)
Probably -- the feature is quite old.
It was introduced in 2000, but I think the mailing list archives on the
FreeBSD website are from 2003. Do you have pointers to any discussions?

(maybe this would be a good opportunity to have some benchmarks and post
them online -- if the original discussion had them and is now lost?)

Thanks,

-e.

--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Elad Efrat
2008-01-29 19:05:58 UTC
Permalink
You asked "Is it possible to hear more about why this is necessary". I
responded that "it is not necessary". Given that I think you probably
misunderstood my response.
I'm sorry then. :)
I'm glad to get you some benchmark numbers. It's not practical for me
to generate them using my actual application for accept filters, mostly
because of the amount of explanation I'd have to provide about how it
works to make its performance metrics interpretable by others. But I
can try to throw something together for you with Apache.
From my point of view, Apache is so much slower than the applications I
deal with that the performance characteristics may be dramatically
different (large Apache configurations seem to handle perhaps 10,000
connections/second; my proprietary application is about an order of
magnitude better, but is not a pure-userspace application). But I will
get you what I can!
I think the effect can be observed using inetd, and that it's a useful
illustration, so I will still polish that code up as, at least, an
example.
Sounds great, thank you!

-e.

--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Thor Lancelot Simon
2008-01-29 19:18:39 UTC
Permalink
Post by Elad Efrat
Obviously I don't, but others do, and I'm merely raising a general
concern saying "let's give this a bit more though" given my -- and I
presume others' -- experience with fun things that can happen due to
improper string handling and/or bugs in privileged code paths. ;)
So, an observation: like a STREAMS module or any other in-kernel
implementation of an application-layer protocol, an accept filter
effectively moves the boundary between user and kernel code in a
network server application.

Because it does that, it is unquestionably the case that it can move
bugs that would be serious -- but for one application -- in a user
application so that they are severe -- for the whole system, without
any protection against propagation of compromise -- bugs in the kernel
instead.

Short of writing the kernel portion of the application code in a safe
language, which we don't really have any facility for, I don't see
any way around this issue int he general case.

It should be copiously noted in the documentation.

Thor

--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Thor Lancelot Simon
2008-01-29 17:21:15 UTC
Permalink
Would it be useful to add explicit sizes for filter length and argument
length?
It would break compatibility with the two other providers of the API. I'd
like it better too. :-/
--
Thor Lancelot Simon ***@rek.tjls.com

"The inconsistency is startling, though admittedly, if consistency is to
be abandoned or transcended, there is no problem." - Noam Chomsky

--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Jason V. Miller
2008-01-29 17:26:35 UTC
Permalink
Yes, as you quoted above, I understand one motivation may be
performance.
Are there any benchmarks done on ~current NetBSD? :)
My understanding is that the dataready filter can be used to prevent the type
of DoS attack that I inquired about in
http://mail-index.netbsd.org/netbsd-help/2005/01/10/0005.html
and where the attacker ties up all available httpd processes on a server.
This obviously helps server performance but may be difficult to quantify in a
benchmark.
If the ``dataready'' filter isn't application specific, you could probably
perform a similar attack by sending a partial HTTP request, though I'm
assuming that ``dataready'' just means accept() won't return until N bytes
of data exist in the receive queue.

A better way to stop the attack described in the referenced post would
probably be with pf(4) and source-track / max-src-states.

J.
--
Jason V. Miller

--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Thor Lancelot Simon
2008-01-29 18:02:08 UTC
Permalink
Post by Darren Reed
Hmmm..
Are you going to contribute (or suggest) changes to the FreeBSD
code based on any changes we might make?
I can suggest. I can't directly contribute -- no privs. Can you?
I think we are going to put a lot of the FreeBSD-specific code back,
#ifdef __FreeBSD__, to make cross-polination easier. It leaves the
file fairly dirty but it also provides a useful example of how they
rearranged a few bits of their stack for socket locking. That will
make feeding changes back a bit simpler, anyway -- smaller diffs.
Please don't clutter the code with #ifdefs.
If I do, it can be the same exact source file for FreeBSD and NetBSD.

If I don't, it can't.

I think in this case it is better to have the same source file. You
do not?
--
Thor Lancelot Simon ***@rek.tjls.com

"The inconsistency is startling, though admittedly, if consistency is to
be abandoned or transcended, there is no problem." - Noam Chomsky

--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
p***@klos.com
2008-01-29 18:25:13 UTC
Permalink
I don't think that the #ifdef clutter is worth it. It has been
tremendously difficult for me to maintain in PF, in IP Filter, and in
net80211. Recently I've had to poke at a lot of ethernet/WLAN drivers,
and the rampant #ifdef'age in cxgb and in if_ndis makes reading and
modifying those drivers as great a chore as dealing with ten less
#ifdef-y drivers.
For what it's worth, cxgb is still a 'work in progress'. We hope to clean
up alot of that mess with OS specific include files rather than the tons
of #ifdef's currently there.

Patrick
========= For LAN/WAN Protocol Analysis, check out PacketView Pro! =========
Patrick Klos Email: ***@klos.com
Network/Embedded Software Engineer Web: http://www.klos.com/
Klos Technologies, Inc. Phone: 603-714-0195
============================================================================

--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Loading...