[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet/accf_http.c

Version: -  FREEBSD  -  FREEBSD10  -  FREEBSD9  -  FREEBSD92  -  FREEBSD91  -  FREEBSD90  -  FREEBSD8  -  FREEBSD82  -  FREEBSD81  -  FREEBSD80  -  FREEBSD7  -  FREEBSD74  -  FREEBSD73  -  FREEBSD72  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  cheribsd  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1  -  FREEBSD-LIBC  -  FREEBSD8-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2000 Paycounter, Inc.
    3  * Author: Alfred Perlstein <alfred@paycounter.com>, <alfred@FreeBSD.org>
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD$");
   30 
   31 #define ACCEPT_FILTER_MOD
   32 
   33 #include <sys/param.h>
   34 #include <sys/kernel.h>
   35 #include <sys/mbuf.h>
   36 #include <sys/module.h>
   37 #include <sys/signalvar.h>
   38 #include <sys/sysctl.h>
   39 #include <sys/socketvar.h>
   40 
   41 /* check for GET/HEAD */
   42 static void sohashttpget(struct socket *so, void *arg, int waitflag);
   43 /* check for HTTP/1.0 or HTTP/1.1 */
   44 static void soparsehttpvers(struct socket *so, void *arg, int waitflag);
   45 /* check for end of HTTP/1.x request */
   46 static void soishttpconnected(struct socket *so, void *arg, int waitflag);
   47 /* strcmp on an mbuf chain */
   48 static int mbufstrcmp(struct mbuf *m, struct mbuf *npkt, int offset, char *cmp);
   49 /* strncmp on an mbuf chain */
   50 static int mbufstrncmp(struct mbuf *m, struct mbuf *npkt, int offset,
   51         int max, char *cmp);
   52 /* socketbuffer is full */
   53 static int sbfull(struct sockbuf *sb);
   54 
   55 static struct accept_filter accf_http_filter = {
   56         "httpready",
   57         sohashttpget,
   58         NULL,
   59         NULL
   60 };
   61 
   62 static moduledata_t accf_http_mod = {
   63         "accf_http",
   64         accept_filt_generic_mod_event,
   65         &accf_http_filter
   66 };
   67 
   68 DECLARE_MODULE(accf_http, accf_http_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
   69 
   70 static int parse_http_version = 1;
   71 
   72 SYSCTL_NODE(_net_inet_accf, OID_AUTO, http, CTLFLAG_RW, 0,
   73 "HTTP accept filter");
   74 SYSCTL_INT(_net_inet_accf_http, OID_AUTO, parsehttpversion, CTLFLAG_RW,
   75 &parse_http_version, 1,
   76 "Parse http version so that non 1.x requests work");
   77 
   78 #ifdef ACCF_HTTP_DEBUG
   79 #define DPRINT(fmt, args...)                                            \
   80         do {                                                            \
   81                 printf("%s:%d: " fmt "\n", __func__, __LINE__, ##args); \
   82         } while (0)
   83 #else
   84 #define DPRINT(fmt, args...)
   85 #endif
   86 
   87 static int
   88 sbfull(struct sockbuf *sb)
   89 {
   90 
   91         DPRINT("sbfull, cc(%ld) >= hiwat(%ld): %d, "
   92             "mbcnt(%ld) >= mbmax(%ld): %d",
   93             sb->sb_cc, sb->sb_hiwat, sb->sb_cc >= sb->sb_hiwat,
   94             sb->sb_mbcnt, sb->sb_mbmax, sb->sb_mbcnt >= sb->sb_mbmax);
   95         return (sb->sb_cc >= sb->sb_hiwat || sb->sb_mbcnt >= sb->sb_mbmax);
   96 }
   97 
   98 /*
   99  * start at mbuf m, (must provide npkt if exists)
  100  * starting at offset in m compare characters in mbuf chain for 'cmp'
  101  */
  102 static int
  103 mbufstrcmp(struct mbuf *m, struct mbuf *npkt, int offset, char *cmp)
  104 {
  105         struct mbuf *n;
  106 
  107         for (; m != NULL; m = n) {
  108                 n = npkt;
  109                 if (npkt)
  110                         npkt = npkt->m_nextpkt;
  111                 for (; m; m = m->m_next) {
  112                         for (; offset < m->m_len; offset++, cmp++) {
  113                                 if (*cmp == '\0')
  114                                         return (1);
  115                                 else if (*cmp != *(mtod(m, char *) + offset))
  116                                         return (0);
  117                         }
  118                         if (*cmp == '\0')
  119                                 return (1);
  120                         offset = 0;
  121                 }
  122         }
  123         return (0);
  124 }
  125 
  126 /*
  127  * start at mbuf m, (must provide npkt if exists)
  128  * starting at offset in m compare characters in mbuf chain for 'cmp'
  129  * stop at 'max' characters
  130  */
  131 static int
  132 mbufstrncmp(struct mbuf *m, struct mbuf *npkt, int offset, int max, char *cmp)
  133 {
  134         struct mbuf *n;
  135 
  136         for (; m != NULL; m = n) {
  137                 n = npkt;
  138                 if (npkt)
  139                         npkt = npkt->m_nextpkt;
  140                 for (; m; m = m->m_next) {
  141                         for (; offset < m->m_len; offset++, cmp++, max--) {
  142                                 if (max == 0 || *cmp == '\0')
  143                                         return (1);
  144                                 else if (*cmp != *(mtod(m, char *) + offset))
  145                                         return (0);
  146                         }
  147                         if (max == 0 || *cmp == '\0')
  148                                 return (1);
  149                         offset = 0;
  150                 }
  151         }
  152         return (0);
  153 }
  154 
  155 #define STRSETUP(sptr, slen, str)                                       \
  156         do {                                                            \
  157                 sptr = str;                                             \
  158                 slen = sizeof(str) - 1;                                 \
  159         } while(0)
  160 
  161 static void
  162 sohashttpget(struct socket *so, void *arg, int waitflag)
  163 {
  164 
  165         if ((so->so_rcv.sb_state & SBS_CANTRCVMORE) == 0 && !sbfull(&so->so_rcv)) {
  166                 struct mbuf *m;
  167                 char *cmp;
  168                 int     cmplen, cc;
  169 
  170                 m = so->so_rcv.sb_mb;
  171                 cc = so->so_rcv.sb_cc - 1;
  172                 if (cc < 1)
  173                         return;
  174                 switch (*mtod(m, char *)) {
  175                 case 'G':
  176                         STRSETUP(cmp, cmplen, "ET ");
  177                         break;
  178                 case 'H':
  179                         STRSETUP(cmp, cmplen, "EAD ");
  180                         break;
  181                 default:
  182                         goto fallout;
  183                 }
  184                 if (cc < cmplen) {
  185                         if (mbufstrncmp(m, m->m_nextpkt, 1, cc, cmp) == 1) {
  186                                 DPRINT("short cc (%d) but mbufstrncmp ok", cc);
  187                                 return;
  188                         } else {
  189                                 DPRINT("short cc (%d) mbufstrncmp failed", cc);
  190                                 goto fallout;
  191                         }
  192                 }
  193                 if (mbufstrcmp(m, m->m_nextpkt, 1, cmp) == 1) {
  194                         DPRINT("mbufstrcmp ok");
  195                         if (parse_http_version == 0)
  196                                 soishttpconnected(so, arg, waitflag);
  197                         else
  198                                 soparsehttpvers(so, arg, waitflag);
  199                         return;
  200                 }
  201                 DPRINT("mbufstrcmp bad");
  202         }
  203 
  204 fallout:
  205         DPRINT("fallout");
  206         so->so_upcall = NULL;
  207         so->so_rcv.sb_flags &= ~SB_UPCALL;
  208         soisconnected(so);
  209         return;
  210 }
  211 
  212 static void
  213 soparsehttpvers(struct socket *so, void *arg, int waitflag)
  214 {
  215         struct mbuf *m, *n;
  216         int     i, cc, spaces, inspaces;
  217 
  218         if ((so->so_rcv.sb_state & SBS_CANTRCVMORE) != 0 || sbfull(&so->so_rcv))
  219                 goto fallout;
  220 
  221         m = so->so_rcv.sb_mb;
  222         cc = so->so_rcv.sb_cc;
  223         inspaces = spaces = 0;
  224         for (m = so->so_rcv.sb_mb; m; m = n) {
  225                 n = m->m_nextpkt;
  226                 for (; m; m = m->m_next) {
  227                         for (i = 0; i < m->m_len; i++, cc--) {
  228                                 switch (*(mtod(m, char *) + i)) {
  229                                 case ' ':
  230                                         /* tabs? '\t' */
  231                                         if (!inspaces) {
  232                                                 spaces++;
  233                                                 inspaces = 1;
  234                                         }
  235                                         break;
  236                                 case '\r':
  237                                 case '\n':
  238                                         DPRINT("newline");
  239                                         goto fallout;
  240                                 default:
  241                                         if (spaces != 2) {
  242                                                 inspaces = 0;
  243                                                 break;
  244                                         }
  245 
  246                                         /*
  247                                          * if we don't have enough characters
  248                                          * left (cc < sizeof("HTTP/1.0") - 1)
  249                                          * then see if the remaining ones
  250                                          * are a request we can parse.
  251                                          */
  252                                         if (cc < sizeof("HTTP/1.0") - 1) {
  253                                                 if (mbufstrncmp(m, n, i, cc,
  254                                                         "HTTP/1.") == 1) {
  255                                                         DPRINT("ok");
  256                                                         goto readmore;
  257                                                 } else {
  258                                                         DPRINT("bad");
  259                                                         goto fallout;
  260                                                 }
  261                                         } else if (
  262                                             mbufstrcmp(m, n, i, "HTTP/1.0") ||
  263                                             mbufstrcmp(m, n, i, "HTTP/1.1")) {
  264                                                         DPRINT("ok");
  265                                                         soishttpconnected(so,
  266                                                             arg, waitflag);
  267                                                         return;
  268                                         } else {
  269                                                 DPRINT("bad");
  270                                                 goto fallout;
  271                                         }
  272                                 }
  273                         }
  274                 }
  275         }
  276 readmore:
  277         DPRINT("readmore");
  278         /*
  279          * if we hit here we haven't hit something
  280          * we don't understand or a newline, so try again
  281          */
  282         so->so_upcall = soparsehttpvers;
  283         so->so_rcv.sb_flags |= SB_UPCALL;
  284         return;
  285 
  286 fallout:
  287         DPRINT("fallout");
  288         so->so_upcall = NULL;
  289         so->so_rcv.sb_flags &= ~SB_UPCALL;
  290         soisconnected(so);
  291         return;
  292 }
  293 
  294 
  295 #define NCHRS 3
  296 
  297 static void
  298 soishttpconnected(struct socket *so, void *arg, int waitflag)
  299 {
  300         char a, b, c;
  301         struct mbuf *m, *n;
  302         int ccleft, copied;
  303 
  304         DPRINT("start");
  305         if ((so->so_rcv.sb_state & SBS_CANTRCVMORE) != 0 || sbfull(&so->so_rcv))
  306                 goto gotit;
  307 
  308         /*
  309          * Walk the socketbuffer and copy the last NCHRS (3) into a, b, and c
  310          * copied - how much we've copied so far
  311          * ccleft - how many bytes remaining in the socketbuffer
  312          * just loop over the mbufs subtracting from 'ccleft' until we only
  313          * have NCHRS left
  314          */
  315         copied = 0;
  316         ccleft = so->so_rcv.sb_cc;
  317         if (ccleft < NCHRS)
  318                 goto readmore;
  319         a = b = c = '\0';
  320         for (m = so->so_rcv.sb_mb; m; m = n) {
  321                 n = m->m_nextpkt;
  322                 for (; m; m = m->m_next) {
  323                         ccleft -= m->m_len;
  324                         if (ccleft <= NCHRS) {
  325                                 char *src;
  326                                 int tocopy;
  327 
  328                                 tocopy = (NCHRS - ccleft) - copied;
  329                                 src = mtod(m, char *) + (m->m_len - tocopy);
  330 
  331                                 while (tocopy--) {
  332                                         switch (copied++) {
  333                                         case 0:
  334                                                 a = *src++;
  335                                                 break;
  336                                         case 1:
  337                                                 b = *src++;
  338                                                 break;
  339                                         case 2:
  340                                                 c = *src++;
  341                                                 break;
  342                                         }
  343                                 }
  344                         }
  345                 }
  346         }
  347         if (c == '\n' && (b == '\n' || (b == '\r' && a == '\n'))) {
  348                 /* we have all request headers */
  349                 goto gotit;
  350         }
  351 
  352 readmore:
  353         so->so_upcall = soishttpconnected;
  354         so->so_rcv.sb_flags |= SB_UPCALL;
  355         return;
  356 
  357 gotit:
  358         so->so_upcall = NULL;
  359         so->so_rcv.sb_flags &= ~SB_UPCALL;
  360         soisconnected(so);
  361         return;
  362 }

Cache object: 6445a37e218c7ac323b9c051fae9c6b6


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.