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 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    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 __FBSDID("$FreeBSD$");
   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/module.h>
   39 #include <sys/signalvar.h>
   40 #include <sys/sysctl.h>
   41 #include <sys/socketvar.h>
   42 
   43 /* check for GET/HEAD */
   44 static int sohashttpget(struct socket *so, void *arg, int waitflag);
   45 /* check for HTTP/1.0 or HTTP/1.1 */
   46 static int soparsehttpvers(struct socket *so, void *arg, int waitflag);
   47 /* check for end of HTTP/1.x request */
   48 static int soishttpconnected(struct socket *so, void *arg, int waitflag);
   49 /* strcmp on an mbuf chain */
   50 static int mbufstrcmp(struct mbuf *m, struct mbuf *npkt, int offset, char *cmp);
   51 /* strncmp on an mbuf chain */
   52 static int mbufstrncmp(struct mbuf *m, struct mbuf *npkt, int offset,
   53         int max, char *cmp);
   54 /* socketbuffer is full */
   55 static int sbfull(struct sockbuf *sb);
   56 
   57 ACCEPT_FILTER_DEFINE(accf_http, "httpready", sohashttpget, NULL, NULL, 1);
   58 
   59 static int parse_http_version = 1;
   60 
   61 static SYSCTL_NODE(_net_inet_accf, OID_AUTO, http,
   62     CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
   63     "HTTP accept filter");
   64 SYSCTL_INT(_net_inet_accf_http, OID_AUTO, parsehttpversion, CTLFLAG_RW,
   65     &parse_http_version, 1,
   66     "Parse http version so that non 1.x requests work");
   67 
   68 #ifdef ACCF_HTTP_DEBUG
   69 #define DPRINT(fmt, args...)                                            \
   70         do {                                                            \
   71                 printf("%s:%d: " fmt "\n", __func__, __LINE__, ##args); \
   72         } while (0)
   73 #else
   74 #define DPRINT(fmt, args...)
   75 #endif
   76 
   77 static int
   78 sbfull(struct sockbuf *sb)
   79 {
   80 
   81         DPRINT("sbfull, cc(%ld) >= hiwat(%ld): %d, "
   82             "mbcnt(%ld) >= mbmax(%ld): %d",
   83             sb->sb_cc, sb->sb_hiwat, sb->sb_cc >= sb->sb_hiwat,
   84             sb->sb_mbcnt, sb->sb_mbmax, sb->sb_mbcnt >= sb->sb_mbmax);
   85         return (sbused(sb) >= sb->sb_hiwat || sb->sb_mbcnt >= sb->sb_mbmax);
   86 }
   87 
   88 /*
   89  * start at mbuf m, (must provide npkt if exists)
   90  * starting at offset in m compare characters in mbuf chain for 'cmp'
   91  */
   92 static int
   93 mbufstrcmp(struct mbuf *m, struct mbuf *npkt, int offset, char *cmp)
   94 {
   95         struct mbuf *n;
   96 
   97         for (; m != NULL; m = n) {
   98                 n = npkt;
   99                 if (npkt)
  100                         npkt = npkt->m_nextpkt;
  101                 for (; m; m = m->m_next) {
  102                         for (; offset < m->m_len; offset++, cmp++) {
  103                                 if (*cmp == '\0')
  104                                         return (1);
  105                                 else if (*cmp != *(mtod(m, char *) + offset))
  106                                         return (0);
  107                         }
  108                         if (*cmp == '\0')
  109                                 return (1);
  110                         offset = 0;
  111                 }
  112         }
  113         return (0);
  114 }
  115 
  116 /*
  117  * start at mbuf m, (must provide npkt if exists)
  118  * starting at offset in m compare characters in mbuf chain for 'cmp'
  119  * stop at 'max' characters
  120  */
  121 static int
  122 mbufstrncmp(struct mbuf *m, struct mbuf *npkt, int offset, int max, char *cmp)
  123 {
  124         struct mbuf *n;
  125 
  126         for (; m != NULL; m = n) {
  127                 n = npkt;
  128                 if (npkt)
  129                         npkt = npkt->m_nextpkt;
  130                 for (; m; m = m->m_next) {
  131                         for (; offset < m->m_len; offset++, cmp++, max--) {
  132                                 if (max == 0 || *cmp == '\0')
  133                                         return (1);
  134                                 else if (*cmp != *(mtod(m, char *) + offset))
  135                                         return (0);
  136                         }
  137                         if (max == 0 || *cmp == '\0')
  138                                 return (1);
  139                         offset = 0;
  140                 }
  141         }
  142         return (0);
  143 }
  144 
  145 #define STRSETUP(sptr, slen, str)                                       \
  146         do {                                                            \
  147                 sptr = str;                                             \
  148                 slen = sizeof(str) - 1;                                 \
  149         } while(0)
  150 
  151 static int
  152 sohashttpget(struct socket *so, void *arg, int waitflag)
  153 {
  154 
  155         if ((so->so_rcv.sb_state & SBS_CANTRCVMORE) == 0 &&
  156             !sbfull(&so->so_rcv)) {
  157                 struct mbuf *m;
  158                 char *cmp;
  159                 int     cmplen, cc;
  160 
  161                 m = so->so_rcv.sb_mb;
  162                 cc = sbavail(&so->so_rcv) - 1;
  163                 if (cc < 1)
  164                         return (SU_OK);
  165                 switch (*mtod(m, char *)) {
  166                 case 'G':
  167                         STRSETUP(cmp, cmplen, "ET ");
  168                         break;
  169                 case 'H':
  170                         STRSETUP(cmp, cmplen, "EAD ");
  171                         break;
  172                 default:
  173                         goto fallout;
  174                 }
  175                 if (cc < cmplen) {
  176                         if (mbufstrncmp(m, m->m_nextpkt, 1, cc, cmp) == 1) {
  177                                 DPRINT("short cc (%d) but mbufstrncmp ok", cc);
  178                                 return (SU_OK);
  179                         } else {
  180                                 DPRINT("short cc (%d) mbufstrncmp failed", cc);
  181                                 goto fallout;
  182                         }
  183                 }
  184                 if (mbufstrcmp(m, m->m_nextpkt, 1, cmp) == 1) {
  185                         DPRINT("mbufstrcmp ok");
  186                         if (parse_http_version == 0)
  187                                 return (soishttpconnected(so, arg, waitflag));
  188                         else
  189                                 return (soparsehttpvers(so, arg, waitflag));
  190                 }
  191                 DPRINT("mbufstrcmp bad");
  192         }
  193 
  194 fallout:
  195         DPRINT("fallout");
  196         return (SU_ISCONNECTED);
  197 }
  198 
  199 static int
  200 soparsehttpvers(struct socket *so, void *arg, int waitflag)
  201 {
  202         struct mbuf *m, *n;
  203         int     i, cc, spaces, inspaces;
  204 
  205         if ((so->so_rcv.sb_state & SBS_CANTRCVMORE) != 0 || sbfull(&so->so_rcv))
  206                 goto fallout;
  207 
  208         m = so->so_rcv.sb_mb;
  209         cc = sbavail(&so->so_rcv);
  210         inspaces = spaces = 0;
  211         for (m = so->so_rcv.sb_mb; m; m = n) {
  212                 n = m->m_nextpkt;
  213                 for (; m; m = m->m_next) {
  214                         for (i = 0; i < m->m_len; i++, cc--) {
  215                                 switch (*(mtod(m, char *) + i)) {
  216                                 case ' ':
  217                                         /* tabs? '\t' */
  218                                         if (!inspaces) {
  219                                                 spaces++;
  220                                                 inspaces = 1;
  221                                         }
  222                                         break;
  223                                 case '\r':
  224                                 case '\n':
  225                                         DPRINT("newline");
  226                                         goto fallout;
  227                                 default:
  228                                         if (spaces != 2) {
  229                                                 inspaces = 0;
  230                                                 break;
  231                                         }
  232 
  233                                         /*
  234                                          * if we don't have enough characters
  235                                          * left (cc < sizeof("HTTP/1.0") - 1)
  236                                          * then see if the remaining ones
  237                                          * are a request we can parse.
  238                                          */
  239                                         if (cc < sizeof("HTTP/1.0") - 1) {
  240                                                 if (mbufstrncmp(m, n, i, cc,
  241                                                         "HTTP/1.") == 1) {
  242                                                         DPRINT("ok");
  243                                                         goto readmore;
  244                                                 } else {
  245                                                         DPRINT("bad");
  246                                                         goto fallout;
  247                                                 }
  248                                         } else if (
  249                                             mbufstrcmp(m, n, i, "HTTP/1.0") ||
  250                                             mbufstrcmp(m, n, i, "HTTP/1.1")) {
  251                                                 DPRINT("ok");
  252                                                 return (soishttpconnected(so,
  253                                                     arg, waitflag));
  254                                         } else {
  255                                                 DPRINT("bad");
  256                                                 goto fallout;
  257                                         }
  258                                 }
  259                         }
  260                 }
  261         }
  262 readmore:
  263         DPRINT("readmore");
  264         /*
  265          * if we hit here we haven't hit something
  266          * we don't understand or a newline, so try again
  267          */
  268         soupcall_set(so, SO_RCV, soparsehttpvers, arg);
  269         return (SU_OK);
  270 
  271 fallout:
  272         DPRINT("fallout");
  273         return (SU_ISCONNECTED);
  274 }
  275 
  276 #define NCHRS 3
  277 
  278 static int
  279 soishttpconnected(struct socket *so, void *arg, int waitflag)
  280 {
  281         char a, b, c;
  282         struct mbuf *m, *n;
  283         int ccleft, copied;
  284 
  285         DPRINT("start");
  286         if ((so->so_rcv.sb_state & SBS_CANTRCVMORE) != 0 || sbfull(&so->so_rcv))
  287                 goto gotit;
  288 
  289         /*
  290          * Walk the socketbuffer and copy the last NCHRS (3) into a, b, and c
  291          * copied - how much we've copied so far
  292          * ccleft - how many bytes remaining in the socketbuffer
  293          * just loop over the mbufs subtracting from 'ccleft' until we only
  294          * have NCHRS left
  295          */
  296         copied = 0;
  297         ccleft = sbavail(&so->so_rcv);
  298         if (ccleft < NCHRS)
  299                 goto readmore;
  300         a = b = c = '\0';
  301         for (m = so->so_rcv.sb_mb; m; m = n) {
  302                 n = m->m_nextpkt;
  303                 for (; m; m = m->m_next) {
  304                         ccleft -= m->m_len;
  305                         if (ccleft <= NCHRS) {
  306                                 char *src;
  307                                 int tocopy;
  308 
  309                                 tocopy = (NCHRS - ccleft) - copied;
  310                                 src = mtod(m, char *) + (m->m_len - tocopy);
  311 
  312                                 while (tocopy--) {
  313                                         switch (copied++) {
  314                                         case 0:
  315                                                 a = *src++;
  316                                                 break;
  317                                         case 1:
  318                                                 b = *src++;
  319                                                 break;
  320                                         case 2:
  321                                                 c = *src++;
  322                                                 break;
  323                                         }
  324                                 }
  325                         }
  326                 }
  327         }
  328         if (c == '\n' && (b == '\n' || (b == '\r' && a == '\n'))) {
  329                 /* we have all request headers */
  330                 goto gotit;
  331         }
  332 
  333 readmore:
  334         soupcall_set(so, SO_RCV, soishttpconnected, arg);
  335         return (SU_OK);
  336 
  337 gotit:
  338         return (SU_ISCONNECTED);
  339 }

Cache object: b534c820e286a81c31f12e20ba0184bb


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