Add an accept filter for TCP based DNS requests. It waits until the

whole first request is present before returning from accept.
This commit is contained in:
David Malone 2008-07-18 14:44:51 +00:00
parent 3b19fa3597
commit 744eaff7e6
7 changed files with 148 additions and 0 deletions

View File

@ -391,6 +391,7 @@ bktr_load="NO" # Brooktree Bt848/Bt878 TV/Video Capture Card
ispfw_load="NO" # Qlogic ISP Firmware
agp_load="NO" # agp module
accf_data_load="NO" # Wait for data accept filter
accf_dns_load="NO" # Wait for data accept filter
accf_http_load="NO" # Wait for full HTTP request accept filter
random_load="NO" # Random device
speaker_load="NO" # AT speaker module

View File

@ -887,6 +887,7 @@ options MBUF_PROFILING
# Statically Link in accept filters
options ACCEPT_FILTER_DATA
options ACCEPT_FILTER_DNS
options ACCEPT_FILTER_HTTP
# TCP_SIGNATURE adds support for RFC 2385 (TCP-MD5) digests. These are

View File

@ -1902,6 +1902,7 @@ netgraph/ng_tee.c optional netgraph_tee
netgraph/ng_tty.c optional netgraph_tty
netgraph/ng_vjc.c optional netgraph_vjc
netinet/accf_data.c optional accept_filter_data
netinet/accf_dns.c optional accept_filter_dns
netinet/accf_http.c optional accept_filter_http
netinet/if_atm.c optional atm
netinet/if_ether.c optional ether

View File

@ -342,6 +342,7 @@ ATA_NOPCI opt_ata.h
# Net stuff.
ACCEPT_FILTER_DATA
ACCEPT_FILTER_DNS
ACCEPT_FILTER_HTTP
ALTQ opt_global.h
ALTQ_CBQ opt_altq.h

View File

@ -6,6 +6,7 @@ SUBDIR= ${_3dfx} \
${_3dfx_linux} \
${_aac} \
accf_data \
accf_dns \
accf_http \
${_acpi} \
age \

View File

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

135
sys/netinet/accf_dns.c Normal file
View File

@ -0,0 +1,135 @@
/*
* Copyright (C) 2007 David Malone <dwmalone@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/kernel.h>
#include <sys/mbuf.h>
#include <sys/module.h>
#include <sys/signalvar.h>
#include <sys/sysctl.h>
#include <sys/socketvar.h>
/* check for full DNS request */
static void sohasdns(struct socket *so, void *arg, int waitflag);
struct packet {
struct mbuf *m; /* Current mbuf. */
struct mbuf *n; /* nextpkt mbuf. */
unsigned long moff; /* Offset of the beginning of m. */
unsigned long offset; /* Which offset we are working at. */
unsigned long len; /* The number of bytes we have to play with. */
};
#define DNS_OK 0
#define DNS_WAIT -1
#define DNS_RUN -2
/* check we can skip over various parts of DNS request */
static int skippacket(struct sockbuf *sb);
static struct accept_filter accf_dns_filter = {
"dnsready",
sohasdns,
NULL,
NULL
};
static moduledata_t accf_dns_mod = {
"accf_dns",
accept_filt_generic_mod_event,
&accf_dns_filter
};
DECLARE_MODULE(accf_dns, accf_dns_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
static void
sohasdns(struct socket *so, void *arg, int waitflag)
{
struct sockbuf *sb = &so->so_rcv;
/* If the socket is full, we're ready. */
if (sb->sb_cc >= sb->sb_hiwat || sb->sb_mbcnt >= sb->sb_mbmax)
goto ready;
/* Check and see if we have a request. */
if (skippacket(sb) == DNS_WAIT)
return;
ready:
so->so_upcall = NULL;
so->so_rcv.sb_flags &= ~SB_UPCALL;
soisconnected(so);
return;
}
#define GET8(p, val) do { \
if (p->offset < p->moff) \
return DNS_RUN; \
while (p->offset >= p->moff + p->m->m_len) { \
p->moff += p->m->m_len; \
p->m = p->m->m_next; \
if (p->m == NULL) { \
p->m = p->n; \
p->n = p->m->m_nextpkt; \
} \
if (p->m == NULL) \
return DNS_WAIT; \
} \
val = *(mtod(p->m, unsigned char *) + (p->offset - p->moff)); \
p->offset++; \
} while (0)
#define GET16(p, val) do { \
unsigned int v0, v1; \
GET8(p, v0); \
GET8(p, v1); \
val = v0 * 0x100 + v1; \
} while (0)
static int
skippacket(struct sockbuf *sb) {
unsigned long packlen;
struct packet q, *p = &q;
if (sb->sb_cc < 2)
return DNS_WAIT;
q.m = sb->sb_mb;
q.n = q.m->m_nextpkt;
q.moff = 0;
q.offset = 0;
q.len = sb->sb_cc;
GET16(p, packlen);
if (packlen + 2 < q.len)
return DNS_WAIT;
return DNS_OK;
}