xref: /freebsd/sys/netinet/accf_dns.c (revision 95ee2897e98f5d444f26ed2334cc7c439f9c16c6)
1  /*-
2   * SPDX-License-Identifier: BSD-2-Clause
3   *
4   * Copyright (C) 2007 David Malone <dwmalone@FreeBSD.org>
5   * All rights reserved.
6   *
7   * Redistribution and use in source and binary forms, with or without
8   * modification, are permitted provided that the following conditions
9   * are met:
10   * 1. Redistributions of source code must retain the above copyright
11   *    notice, this list of conditions and the following disclaimer.
12   * 2. Redistributions in binary form must reproduce the above copyright
13   *    notice, this list of conditions and the following disclaimer in the
14   *    documentation and/or other materials provided with the distribution.
15   *
16   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19   * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26   * SUCH DAMAGE.
27   */
28  
29  #define ACCEPT_FILTER_MOD
30  
31  #include <sys/param.h>
32  #include <sys/kernel.h>
33  #include <sys/mbuf.h>
34  #include <sys/module.h>
35  #include <sys/signalvar.h>
36  #include <sys/sysctl.h>
37  #include <sys/socketvar.h>
38  
39  /* check for full DNS request */
40  static int sohasdns(struct socket *so, void *arg, int waitflag);
41  
42  ACCEPT_FILTER_DEFINE(accf_dns, "dnsready", sohasdns, NULL, NULL, 1);
43  
44  struct packet {
45  	struct mbuf *m;		/* Current mbuf. */
46  	struct mbuf *n;		/* nextpkt mbuf. */
47  	unsigned long moff;	/* Offset of the beginning of m. */
48  	unsigned long offset;	/* Which offset we are working at. */
49  	unsigned long len;	/* The number of bytes we have to play with. */
50  };
51  
52  #define DNS_OK 0
53  #define DNS_WAIT -1
54  #define DNS_RUN -2
55  
56  /* check we can skip over various parts of DNS request */
57  static int skippacket(struct sockbuf *sb);
58  
59  static int
sohasdns(struct socket * so,void * arg,int waitflag)60  sohasdns(struct socket *so, void *arg, int waitflag)
61  {
62  	struct sockbuf *sb = &so->so_rcv;
63  
64  	/* If the socket is full, we're ready. */
65  	if (sbused(sb) >= sb->sb_hiwat || sb->sb_mbcnt >= sb->sb_mbmax)
66  		goto ready;
67  
68  	/* Check to see if we have a request. */
69  	if (skippacket(sb) == DNS_WAIT)
70  		return (SU_OK);
71  
72  ready:
73  	return (SU_ISCONNECTED);
74  }
75  
76  #define GET8(p, val) do { \
77  	if (p->offset < p->moff) \
78  		return DNS_RUN; \
79  	while (p->offset >= p->moff + p->m->m_len) { \
80  		p->moff += p->m->m_len; \
81  		p->m = p->m->m_next; \
82  		if (p->m == NULL) { \
83  			p->m = p->n; \
84  			p->n = p->m->m_nextpkt; \
85  		} \
86  		if (p->m == NULL) \
87  			return DNS_WAIT; \
88  	} \
89  	val = *(mtod(p->m, unsigned char *) + (p->offset - p->moff)); \
90  	p->offset++; \
91  	} while (0)
92  
93  #define GET16(p, val) do { \
94  	unsigned int v0, v1; \
95  	GET8(p, v0); \
96  	GET8(p, v1); \
97  	val = v0 * 0x100 + v1; \
98  	} while (0)
99  
100  static int
skippacket(struct sockbuf * sb)101  skippacket(struct sockbuf *sb) {
102  	unsigned long packlen;
103  	struct packet q, *p = &q;
104  
105  	if (sbavail(sb) < 2)
106  		return DNS_WAIT;
107  
108  	q.m = sb->sb_mb;
109  	q.n = q.m->m_nextpkt;
110  	q.moff = 0;
111  	q.offset = 0;
112  	q.len = sbavail(sb);
113  
114  	GET16(p, packlen);
115  	if (packlen + 2 > q.len)
116  		return DNS_WAIT;
117  
118  	return DNS_OK;
119  }
120