The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ 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  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 56dfeb7a9d6b7d8fbeb9496c5d699f91


[ 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.