xref: /freebsd/sys/netinet/accf_http.c (revision a79b71281cd63ad7a6cc43a6d5673a2510b51630)
1a79b7128SAlfred Perlstein /*-
2a79b7128SAlfred Perlstein  * Copyright (c) 2000 Alfred Perlstein <alfred@FreeBSD.org>
3a79b7128SAlfred Perlstein  * All rights reserved.
4a79b7128SAlfred Perlstein  *
5a79b7128SAlfred Perlstein  * Redistribution and use in source and binary forms, with or without
6a79b7128SAlfred Perlstein  * modification, are permitted provided that the following conditions
7a79b7128SAlfred Perlstein  * are met:
8a79b7128SAlfred Perlstein  * 1. Redistributions of source code must retain the above copyright
9a79b7128SAlfred Perlstein  *    notice, this list of conditions and the following disclaimer.
10a79b7128SAlfred Perlstein  * 2. Redistributions in binary form must reproduce the above copyright
11a79b7128SAlfred Perlstein  *    notice, this list of conditions and the following disclaimer in the
12a79b7128SAlfred Perlstein  *    documentation and/or other materials provided with the distribution.
13a79b7128SAlfred Perlstein  *
14a79b7128SAlfred Perlstein  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15a79b7128SAlfred Perlstein  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16a79b7128SAlfred Perlstein  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17a79b7128SAlfred Perlstein  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18a79b7128SAlfred Perlstein  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19a79b7128SAlfred Perlstein  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20a79b7128SAlfred Perlstein  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21a79b7128SAlfred Perlstein  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22a79b7128SAlfred Perlstein  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23a79b7128SAlfred Perlstein  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24a79b7128SAlfred Perlstein  * SUCH DAMAGE.
25a79b7128SAlfred Perlstein  *
26a79b7128SAlfred Perlstein  *	$FreeBSD$
27a79b7128SAlfred Perlstein  */
28a79b7128SAlfred Perlstein 
29a79b7128SAlfred Perlstein #define ACCEPT_FILTER_MOD
30a79b7128SAlfred Perlstein 
31a79b7128SAlfred Perlstein #include <sys/param.h>
32a79b7128SAlfred Perlstein #include <sys/systm.h>
33a79b7128SAlfred Perlstein #include <sys/sysproto.h>
34a79b7128SAlfred Perlstein #include <sys/kernel.h>
35a79b7128SAlfred Perlstein #include <sys/proc.h>
36a79b7128SAlfred Perlstein #include <sys/malloc.h>
37a79b7128SAlfred Perlstein #include <sys/unistd.h>
38a79b7128SAlfred Perlstein #include <sys/file.h>
39a79b7128SAlfred Perlstein #include <sys/fcntl.h>
40a79b7128SAlfred Perlstein #include <sys/protosw.h>
41a79b7128SAlfred Perlstein #include <sys/socket.h>
42a79b7128SAlfred Perlstein #include <sys/socketvar.h>
43a79b7128SAlfred Perlstein #include <sys/stat.h>
44a79b7128SAlfred Perlstein #include <sys/mbuf.h>
45a79b7128SAlfred Perlstein #include <sys/resource.h>
46a79b7128SAlfred Perlstein #include <sys/sysent.h>
47a79b7128SAlfred Perlstein #include <sys/resourcevar.h>
48a79b7128SAlfred Perlstein 
49a79b7128SAlfred Perlstein /*
50a79b7128SAlfred Perlstein  * XXX: doesn't work with 0.9 requests, make a seperate filter
51a79b7128SAlfred Perlstein  * based on this one if you want to decode those.
52a79b7128SAlfred Perlstein  */
53a79b7128SAlfred Perlstein 
54a79b7128SAlfred Perlstein /* check for GET */
55a79b7128SAlfred Perlstein static void sohashttpget(struct socket *so, void *arg, int waitflag);
56a79b7128SAlfred Perlstein /* check for end of HTTP request */
57a79b7128SAlfred Perlstein static void soishttpconnected(struct socket *so, void *arg, int waitflag);
58a79b7128SAlfred Perlstein static char sbindex(struct mbuf **mp, int *begin, int end);
59a79b7128SAlfred Perlstein 
60a79b7128SAlfred Perlstein static struct accept_filter accf_http_filter = {
61a79b7128SAlfred Perlstein 	"httpready",
62a79b7128SAlfred Perlstein 	sohashttpget,
63a79b7128SAlfred Perlstein 	NULL,
64a79b7128SAlfred Perlstein 	NULL
65a79b7128SAlfred Perlstein };
66a79b7128SAlfred Perlstein 
67a79b7128SAlfred Perlstein static moduledata_t accf_http_mod = {
68a79b7128SAlfred Perlstein 	"accf_http",
69a79b7128SAlfred Perlstein 	accept_filt_generic_mod_event,
70a79b7128SAlfred Perlstein 	&accf_http_filter
71a79b7128SAlfred Perlstein };
72a79b7128SAlfred Perlstein 
73a79b7128SAlfred Perlstein DECLARE_MODULE(accf_http, accf_http_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
74a79b7128SAlfred Perlstein 
75a79b7128SAlfred Perlstein 
76a79b7128SAlfred Perlstein static char
77a79b7128SAlfred Perlstein sbindex(struct mbuf **mp, int *begin, int end)
78a79b7128SAlfred Perlstein {
79a79b7128SAlfred Perlstein 	struct mbuf *m = *mp;
80a79b7128SAlfred Perlstein 	int diff = end - *begin + 1;
81a79b7128SAlfred Perlstein 
82a79b7128SAlfred Perlstein 	while (m->m_len < diff) {
83a79b7128SAlfred Perlstein 		*begin += m->m_len;
84a79b7128SAlfred Perlstein 		diff -= m->m_len;
85a79b7128SAlfred Perlstein 		if (m->m_next) {
86a79b7128SAlfred Perlstein 			m = m->m_next;
87a79b7128SAlfred Perlstein 		} else if (m->m_nextpkt) {
88a79b7128SAlfred Perlstein 			m = m->m_nextpkt;
89a79b7128SAlfred Perlstein 		} else {
90a79b7128SAlfred Perlstein 			/* only happens if end > data in socket buffer */
91a79b7128SAlfred Perlstein 			panic("sbindex: not enough data");
92a79b7128SAlfred Perlstein 		}
93a79b7128SAlfred Perlstein 	}
94a79b7128SAlfred Perlstein 	*mp = m;
95a79b7128SAlfred Perlstein 	return *(mtod(m, char *) + diff - 1);
96a79b7128SAlfred Perlstein }
97a79b7128SAlfred Perlstein 
98a79b7128SAlfred Perlstein static void
99a79b7128SAlfred Perlstein sohashttpget(struct socket *so, void *arg, int waitflag)
100a79b7128SAlfred Perlstein {
101a79b7128SAlfred Perlstein 
102a79b7128SAlfred Perlstein 	if ((so->so_state & SS_CANTRCVMORE) == 0) {
103a79b7128SAlfred Perlstein 		struct mbuf *m;
104a79b7128SAlfred Perlstein 
105a79b7128SAlfred Perlstein 		if (so->so_rcv.sb_cc < 6)
106a79b7128SAlfred Perlstein 			return;
107a79b7128SAlfred Perlstein 		m = so->so_rcv.sb_mb;
108a79b7128SAlfred Perlstein 		if (bcmp(mtod(m, char *), "GET ", 4) == 0) {
109a79b7128SAlfred Perlstein 			soishttpconnected(so, arg, waitflag);
110a79b7128SAlfred Perlstein 			return;
111a79b7128SAlfred Perlstein 		}
112a79b7128SAlfred Perlstein 	}
113a79b7128SAlfred Perlstein 
114a79b7128SAlfred Perlstein 	so->so_upcall = NULL;
115a79b7128SAlfred Perlstein 	so->so_rcv.sb_flags &= ~SB_UPCALL;
116a79b7128SAlfred Perlstein 	soisconnected(so);
117a79b7128SAlfred Perlstein 	return;
118a79b7128SAlfred Perlstein }
119a79b7128SAlfred Perlstein 
120a79b7128SAlfred Perlstein static void
121a79b7128SAlfred Perlstein soishttpconnected(struct socket *so, void *arg, int waitflag)
122a79b7128SAlfred Perlstein {
123a79b7128SAlfred Perlstein 	char a, b, c;
124a79b7128SAlfred Perlstein 	struct mbuf *y, *z;
125a79b7128SAlfred Perlstein 
126a79b7128SAlfred Perlstein 	if ((so->so_state & SS_CANTRCVMORE) == 0) {
127a79b7128SAlfred Perlstein 		/* seek to end and keep track of next to last mbuf */
128a79b7128SAlfred Perlstein 		y = so->so_rcv.sb_mb;
129a79b7128SAlfred Perlstein 		while (y->m_nextpkt)
130a79b7128SAlfred Perlstein 			y = y->m_nextpkt;
131a79b7128SAlfred Perlstein 		z = y;
132a79b7128SAlfred Perlstein 		while (y->m_next) {
133a79b7128SAlfred Perlstein 			z = y;
134a79b7128SAlfred Perlstein 			y = y->m_next;
135a79b7128SAlfred Perlstein 		}
136a79b7128SAlfred Perlstein 
137a79b7128SAlfred Perlstein 		if (z->m_len + y->m_len > 2) {
138a79b7128SAlfred Perlstein 			int index = y->m_len - 1;
139a79b7128SAlfred Perlstein 
140a79b7128SAlfred Perlstein 			c = *(mtod(y, char *) + index--);
141a79b7128SAlfred Perlstein 			switch (index) {
142a79b7128SAlfred Perlstein 			case -1:
143a79b7128SAlfred Perlstein 				y = z;
144a79b7128SAlfred Perlstein 				index = y->m_len - 1;
145a79b7128SAlfred Perlstein 				b = *(mtod(y, char *) + index--);
146a79b7128SAlfred Perlstein 				break;
147a79b7128SAlfred Perlstein 			case 0:
148a79b7128SAlfred Perlstein 				b = *(mtod(y, char *) + index--);
149a79b7128SAlfred Perlstein 				y = z;
150a79b7128SAlfred Perlstein 				index = y->m_len - 1;
151a79b7128SAlfred Perlstein 				break;
152a79b7128SAlfred Perlstein 			default:
153a79b7128SAlfred Perlstein 				b = *(mtod(y, char *) + index--);
154a79b7128SAlfred Perlstein 				break;
155a79b7128SAlfred Perlstein 			}
156a79b7128SAlfred Perlstein 			a = *(mtod(y, char *) + index--);
157a79b7128SAlfred Perlstein 		} else {
158a79b7128SAlfred Perlstein 			int begin = 0;
159a79b7128SAlfred Perlstein 			int end = so->so_rcv.sb_cc - 3;
160a79b7128SAlfred Perlstein 
161a79b7128SAlfred Perlstein 			y = so->so_rcv.sb_mb;
162a79b7128SAlfred Perlstein 			a = sbindex(&y, &begin, end++);
163a79b7128SAlfred Perlstein 			b = sbindex(&y, &begin, end++);
164a79b7128SAlfred Perlstein 			c = sbindex(&y, &begin, end++);
165a79b7128SAlfred Perlstein 		}
166a79b7128SAlfred Perlstein 
167a79b7128SAlfred Perlstein 		if (c == '\n' && (b == '\n' || (b == '\r' && a == '\n'))) {
168a79b7128SAlfred Perlstein 			/* we have all request headers */
169a79b7128SAlfred Perlstein 			goto done;
170a79b7128SAlfred Perlstein 		} else {
171a79b7128SAlfred Perlstein 			/* still need more data */
172a79b7128SAlfred Perlstein 			so->so_upcall = soishttpconnected;
173a79b7128SAlfred Perlstein 			so->so_rcv.sb_flags |= SB_UPCALL;
174a79b7128SAlfred Perlstein 			return;
175a79b7128SAlfred Perlstein 		}
176a79b7128SAlfred Perlstein 	}
177a79b7128SAlfred Perlstein 
178a79b7128SAlfred Perlstein done:
179a79b7128SAlfred Perlstein 	so->so_upcall = NULL;
180a79b7128SAlfred Perlstein 	so->so_rcv.sb_flags &= ~SB_UPCALL;
181a79b7128SAlfred Perlstein 	soisconnected(so);
182a79b7128SAlfred Perlstein 	return;
183a79b7128SAlfred Perlstein }
184