欢迎来到虫虫下载站 | 资源下载 资源专辑 关于我们
虫虫下载站

http.c

Google 推出一套免費的 Web 安全評估工具
C
第 1 页 / 共 3 页
字号:
/*   ratproxy - HTTP request handling   --------------------------------   The following routines take care of HTTP request handling, parsing,   and error reporting.   Note that this code is one-shot, process is terminated when request   handling is done - and as such, we rely on the OS to do garbage   collection.   Author: Michal Zalewski <lcamtuf@google.com>   Copyright 2007, 2008 by Google Inc. All Rights Reserved.   Licensed under the Apache License, Version 2.0 (the "License");   you may not use this file except in compliance with the License.   You may obtain a copy of the License at     http://www.apache.org/licenses/LICENSE-2.0   Unless required by applicable law or agreed to in writing, software   distributed under the License is distributed on an "AS IS" BASIS,   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   See the License for the specific language governing permissions and   limitations under the License. */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/socket.h>#include <netinet/in.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <string.h>#include <sys/wait.h>#include <ctype.h>#include <netdb.h>#include <openssl/md5.h>#include <time.h>#include "config.h"#include "types.h"#include "debug.h"#include "nlist.h"#include "http.h"#include "ssl.h"#include "string-inl.h"extern _u8* use_proxy;		/* Runtime setting exports from ratproxy. */extern _u32 proxy_port;extern _u8  use_len;static _u8 srv_buf[MAXLINE],	/* libc IO buffers */           cli_buf[MAXLINE];/* Read a single line of HTTP headers, strip whitespaces */static _u8* grab_line(FILE* where) {  static _u8 inbuf[MAXLINE];  _u32 l;  if (!fgets(inbuf,MAXLINE,where)) return 0;  l = strlen(inbuf);  /* Excessive line length is bad, let's bail out. */  if (l == MAXLINE-1) return 0;  while (l && isspace(inbuf[l-1])) inbuf[--l] = 0;  return inbuf;}/* Return a generic HTTP error message, end current process.   Note that this function should not handle user-controlled data. */static void http_error(FILE* client, _u8* message,_u8 sink) {  if (client) {    _u8* l;     if (sink) while ((l=grab_line(client)) && l[0]);    fprintf(client,      "HTTP/1.0 500 %s\n"      "Content-type: text/html\n\n"            "<font face=\"Bitstream Vera Sans Mono,Andale Mono,Lucida Console\">\n"      "The proxy is unable to process your request.\n"      "<h1><font color=red><b>%s.</b></font></h1>\n", message, message);    fflush(client);    fclose(client);   }  debug("[!] WARNING: %s.\n", message);  exit(0);}static _u8* BASE16 = "0123456789ABCDEF";/* Decode URL-encoded parameter string */void parse_urlencoded(struct naive_list_p* p, _u8* string) {  _u8 val_now = 0;  _u8 name[MAXLINE+1], val[MAXLINE+1];  _u32 nlen = 0, vlen = 0;  name[0] = 0;  val[0] = 0;  do {    _u8 dec = 0;    switch (*string) {      case '+':        dec = ' ';        break;      case '=':        val_now = 1;        break;      case '%': {          _u8 *a, *b;          /* Parse %nn code, if valid; default to '?nn' if not, replace with ? if \0. */          if (!string[1] || !string[2] || !(a=strchr(BASE16,toupper(string[1]))) ||              !(b=strchr(BASE16,toupper(string[2])))) { dec = '?'; break; }          dec = (a-BASE16) * 16 + (b-BASE16);          string += 2;          if (!dec) dec = '?';          break;        }      case '&':      case 0:        /* Handle parameter terminator; note that we also iterate over \0           because of loop condition placement. */        if (nlen) {          name[nlen] = 0;          val[vlen] = 0;          DYN_ADDP(*p,name,val,"");        }        val_now = 0;        nlen = 0;        vlen = 0;        break;      default:        if (!(dec=*string)) dec = '?';    }    /* Append decoded char, if any, to field name or value as needed. */    if (dec) {      if (!val_now) { if (nlen < MAXLINE) name[nlen++] = dec; }        else { if (vlen < MAXLINE) val[vlen++] = dec; }    }  } while (*(string++));  }/* Read a line of multipart data from a linear buffer, advance buffer pointer. */static _u8* get_multipart_line(_u8** buf) {  static _u8* retbuf;  _u8* x;  _u32 cnt;  if (retbuf) free(retbuf);  /* We assume \r\n formatting here, which is RFC-mandated and implemtned     by well-behaved browsers. */  x = strchr(*buf,'\r');  if (!x || x[1] != '\n') {    _u32 l = strlen(*buf);    retbuf = malloc(l + 1);    if (!retbuf) fatal("out of memory");    strcpy(retbuf,*buf);    *buf += l;    return retbuf;  }  cnt = x - *buf;  retbuf = malloc(cnt + 1);  if (!retbuf) fatal("out of memory");  memcpy(retbuf,*buf,cnt);  retbuf[cnt] = 0;  *buf += cnt + 2;  return retbuf;}/* Collect multipart data from a reasonably well-behaved browser. This routine   makes multiple assumptions that might be not true for maliciously formatted   data, but we do not strive to serve such requests well. */void parse_multipart(struct naive_list_p* p, _u8* string, _u32 slen) {  _u8* field, *fname;  _u8* endptr = string + slen;  do {    _u8 *l, *end, *c;    field = 0;    fname = 0;    /* Skip boundary */    l = get_multipart_line(&string);    if (l[0] != '-' || l[1] != '-') return;    /* Sink headers, but grab field name if any */    while ((l = get_multipart_line(&string)) && l[0]) {      if (!strncasecmp(l,"Content-Disposition:",20)) {        /* Grab field name. */        _u8* f = rp_strcasestr(l,"; name=\"");        if (!f) continue;        f += 7;        c = strchr(++f,'"');        if (!c) continue;        *c = 0;                  field = strdup(f);        if (!field) fatal("out of memory");        /* Grab file name, if any. */        f = rp_strcasestr(c + 1,"; filename=\"");        if (!f) continue;        f += 11;        c = strchr(++f,'"');        if (!c) continue;        *c = 0;        fname = strdup(f);        if (!fname) fatal("out of memory");      }    }    end = rp_memmem(string,endptr - string, "\r\n--", 4);    if (!end) return;    if (field)       DYN_ADDP_RAWMEM(*p,field,string,end-string,fname ? fname : (_u8*)"");    string = end + 2;  } while (1);}#define BASE64 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+/_-"/* Looks for what could pass for a reasonably robust session token or XSRF protection. */_u8 contains_token(_u8* name, _u8* value) {  _u32 run16 = 0, run64 = 0, run64_true = 0, run64_num = 0, run64_up = 0;  _u8* st = 0;  static _u32 tmin,tmax;  _u32 fno = 0;  if (!tmin) {    tmin = time(0);    tmax = tmin + (60 * 60 * 24 * 30); /* One month forward */    tmin -= (60 * 60 * 24 * 365 * 5);  /* Five years back */  }  /* Known bad field names - return 0. */  fno = 0;  while (no_xsrf_fields[fno]) {    if (no_xsrf_fields[fno][0] == '=') {      if (!strcasecmp(name,no_xsrf_fields[fno] + 1)) return 0;    } else {      if (rp_strcasestr(name,no_xsrf_fields[fno])) return 0;    }    fno++;  }  /* Known safe field names - return 1. */  fno = 0;  while (xsrf_fields[fno]) {    if (xsrf_fields[fno][0] == '=') {      if (!strcasecmp(name,xsrf_fields[fno] + 1)) return 1;    } else {      if (rp_strcasestr(name,xsrf_fields[fno])) return 1;    }    fno++;  }  /* URLs are not anti-XSRF tokens, no matter how random they look. */  if (!strncmp(value,"http",4)) return 0;  /* Iterate over value data, compute base16 / base64 runs, collect     basic character disttributin data, rule out patterns such as unix      time, and make the call. */  do {    if (*value && strchr(BASE16,toupper(*value))) {      run16++;     } else {      if (run16 >= XSRF_B16_MIN && run16 <= XSRF_B16_MAX) {        _u8 tmp[5];        _u32 val;        strncpy(tmp,st,4);        tmp[4] = 0;        val = atoi(tmp);         if ((val < tmin / 1000000 || val > tmax / 1000000) &&            (st[0] != st[1] || st[0] != st[2])) return 1;      }      run16 = 0;    }    if (*value && strchr(BASE64,toupper(*value))) {      if (!isalpha(*value)) run64_num++;      if (isupper(*value)) run64_up++;      if (!run16) run64_true = 1;      if (!run64) st = value;      run64++;    } else {      if (run64 >= XSRF_B64_MIN && run64 <= XSRF_B64_MAX &&           ((run64_num >= XSRF_B64_NUM && run64_up >= XSRF_B64_UP) ||            (run64_num >= XSRF_B64_NUM2)) && run64_true)         if (st[0] != st[1] || st[0] != st[2]) return 1;      run64 = 0;      run64_num = 0;      run64_true = 0;      st = 0;    }  } while (*(value++));  return 0;}/* Try to parse cookie header values. */static void parse_cookies(_u8* str, struct naive_list2* c) {  _u8 name[128], val[128];  /* Iterate over cookies. We ignore cookies over 128 bytes for     name / value, and "special" values such as expiration date,     version, etc. */  while (str) {    while (isspace(*str)) str++;    if (sscanf(str,"%127[^;=]=%127[^;]",name,val) == 2) {      if (strcasecmp(name,"expires") && strcasecmp(name,"comment") &&          strcasecmp(name,"version") && strcasecmp(name,"max-age") &&          strcasecmp(name,"path") && strcasecmp(name,"domain") && name[0] != '$')        DYN_ADD2(*c,name,val);    }    str = strchr(str + 1 ,';');    if (str) str++;  }}/* Process the entire HTTP request, parse fields, and extract some preliminary signals. */struct http_request* collect_request(FILE* client,_u8* ssl_host, _u32 ssl_port) {  struct http_request* ret;  _u8 *line, *x;  _u32 i;  /* Begin carefully - on CONNECT requests, we do not want to read more than     absolutely necessary. As soon as non-CONNECT is confirmed, we switch     to proper buffering. */  setvbuf(client, cli_buf, _IONBF, 0);  ret = calloc(1, sizeof(struct http_request));  if (!ret) fatal("out of memory");  line = grab_line(client);  if (!line || !line[0]) exit(0);  x = strchr(line,' ');  if (!x || x == line) http_error(client, "URL address missing or malformed request",1);  *(x++) = 0;  ret->method = strdup(line);  if (!ret->method) fatal("out of memory");  if (strcmp(line,"CONNECT")) {    /* Ok, safe to handle HTTP at full speed now. */    setvbuf(client, cli_buf, _IOFBF, sizeof(cli_buf));    if (!ssl_host) {      /* Unless coming from within CONNECT, we want a         properly specified protocol and so forth. */      if (x[0] == '/')         http_error(client, "Direct HTTP requests not allowed",1);      if (strncmp(x,"http://",7))        http_error(client, "Unsupported protocol",1);      x += 7;    }  } else {    /* We do not want CONNECT requests within CONNECT requests, really. */     if (ssl_host) http_error(client,"Evil CONNECT nesting",1);    ret->is_connect = 1;  }  ret->host = x;  x = strchr(ret->host,' ');  if (!x) http_error(client,"Missing HTTP protocol version",1);  if (strcmp(x," HTTP/1.0") && strcmp(x," HTTP/1.1"))    http_error(client,"unsupported HTTP protocol version",1);  /* Trim HTTP/1.x part now, we do not need it */  *x = 0;     if (!ret->is_connect) {    ret->path = strchr(ret->host,'/');    if (!ret->path) http_error(client,"Incomplete request URL",1);    *(ret->path++) = 0;  }  /* Try to find port, if any */  x = strchr(ret->host,':');  if (x) {     ret->port = atoi(x+1);    if (!ret->port || ret->port > 65535)       http_error(client,"Illegal port specification",1);    if (ret->port < 1024 && ret->port != 80 && ret->port != 443)      http_error(client,"Access to this port denied",1);    *x = 0;   } else {    if (ret->is_connect) ret->port = 443;      else ret->port = 80;  }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -