/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (C) 2007 David Malone <[email protected]>4* All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11* 2. Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in the13* documentation and/or other materials provided with the distribution.14*15* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND16* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE17* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE18* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE19* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL20* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS21* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)22* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT23* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY24* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF25* SUCH DAMAGE.26*/2728#define ACCEPT_FILTER_MOD2930#include <sys/param.h>31#include <sys/kernel.h>32#include <sys/mbuf.h>33#include <sys/module.h>34#include <sys/signalvar.h>35#include <sys/sysctl.h>36#include <sys/socketvar.h>3738/* check for full DNS request */39static int sohasdns(struct socket *so, void *arg, int waitflag);4041ACCEPT_FILTER_DEFINE(accf_dns, "dnsready", sohasdns, NULL, NULL, 1);4243struct packet {44struct mbuf *m; /* Current mbuf. */45struct mbuf *n; /* nextpkt mbuf. */46unsigned long moff; /* Offset of the beginning of m. */47unsigned long offset; /* Which offset we are working at. */48unsigned long len; /* The number of bytes we have to play with. */49};5051#define DNS_OK 052#define DNS_WAIT -153#define DNS_RUN -25455/* check we can skip over various parts of DNS request */56static int skippacket(struct sockbuf *sb);5758static int59sohasdns(struct socket *so, void *arg, int waitflag)60{61struct sockbuf *sb = &so->so_rcv;6263/* If the socket is full, we're ready. */64if (sbused(sb) >= sb->sb_hiwat || sb->sb_mbcnt >= sb->sb_mbmax)65goto ready;6667/* Check to see if we have a request. */68if (skippacket(sb) == DNS_WAIT)69return (SU_OK);7071ready:72return (SU_ISCONNECTED);73}7475#define GET8(p, val) do { \76if (p->offset < p->moff) \77return DNS_RUN; \78while (p->offset >= p->moff + p->m->m_len) { \79p->moff += p->m->m_len; \80p->m = p->m->m_next; \81if (p->m == NULL) { \82p->m = p->n; \83p->n = p->m->m_nextpkt; \84} \85if (p->m == NULL) \86return DNS_WAIT; \87} \88val = *(mtod(p->m, unsigned char *) + (p->offset - p->moff)); \89p->offset++; \90} while (0)9192#define GET16(p, val) do { \93unsigned int v0, v1; \94GET8(p, v0); \95GET8(p, v1); \96val = v0 * 0x100 + v1; \97} while (0)9899static int100skippacket(struct sockbuf *sb) {101unsigned long packlen;102struct packet q, *p = &q;103104if (sbavail(sb) < 2)105return DNS_WAIT;106107q.m = sb->sb_mb;108q.n = q.m->m_nextpkt;109q.moff = 0;110q.offset = 0;111q.len = sbavail(sb);112113GET16(p, packlen);114if (packlen + 2 > q.len)115return DNS_WAIT;116117return DNS_OK;118}119120121