/* doscan - Denial Of Service Capable Auditing of Networks * Copyright (C) 2003 Florian Weimer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* This is a simple HTTP version string collector, intended as sample code for the TCP engine code. */ #include "config.h" #include "engine_tcp.h" #include "opt.h" #include "proto.h" #include "results.h" #include "scan.h" #include "utils.h" #include static bool http_start (subnets&); static void http_open (scan_host_t *); static void http_send_request (scan_host_t *); static void http_receive_reply (scan_host_t *); static void http_finish (scan_host_t *, const char *buffer, unsigned size); static char *request_buffer; static unsigned request_size; static pcre *end_regexp; static pcre *server_regexp; void proto_http_register (void) { proto_register ("http", http_start, http_open); } static bool http_start (subnets&) { const char *errptr; int erroffset; if (opt_banner_size == 0) { opt_banner_size = 4000; } if (opt_send && (opt_send[0] != '\0')) { string_dequote (opt_send, &request_buffer, &request_size, "--send option"); } else { string_dequote ("GET / HTTP/1.0\\r\\n\\r\\n", &request_buffer, &request_size, "--send option"); } if (opt_receive && (opt_receive[0] != '\0')) { fprintf (stderr, "%s: http protocol module does not support --receive\n", opt_program); exit (EXIT_FAILURE); } end_regexp = pcre_compile ("(.*?)\r\n\r\n", PCRE_ANCHORED | PCRE_DOLLAR_ENDONLY | PCRE_DOTALL, &errptr, &erroffset, 0); server_regexp = pcre_compile (".*\r\nServer:[\t ]*(.*?)[\t ]*\r\n", PCRE_ANCHORED | PCRE_DOLLAR_ENDONLY | PCRE_DOTALL, &errptr, &erroffset, 0); if (! (end_regexp && server_regexp)) { fprintf (stderr, "%s: fatal PCRE error\n", opt_program); exit (EXIT_FAILURE); } return true; } static void http_open (scan_host_t *s) { if (!s->state) { s->state = malloc (sizeof (engine_tcp_t)); } engine_tcp_open (s, http_send_request, http_receive_reply); } static void http_send_request (scan_host_t *s) { engine_tcp_send (s, request_buffer, request_size, ENGINE_TCP_NO_COPY, http_receive_reply); } static void http_receive_reply (scan_host_t *s) { engine_tcp_receive_until_match (s, end_regexp, 0, opt_banner_size, http_finish); } static void http_finish (scan_host_t *s, const char *buffer, unsigned size) { int ovector[6]; int rc; unsigned header_length; /* First determine the end of the header. */ rc = pcre_exec (end_regexp, 0, buffer, size, 0, 0, ovector, 6); if (rc != 2) { fprintf (stderr, "%s: internal error %d in http protocol module\n", opt_program, rc); exit (EXIT_FAILURE); } if (ovector[2] != 0) { fprintf (stderr, "%s: internal match error in http protocol module\n", opt_program); exit (EXIT_FAILURE); } header_length = ovector[3]; /* Then look for the Server: string in the header. */ rc = pcre_exec (server_regexp, 0, buffer, header_length, 0, 0, ovector, 6); switch (rc) { case 2: results_add (ticks_get_cached (), s->host, 0, buffer + ovector[2], ovector[3] - ovector[2]); break; case PCRE_ERROR_NOMATCH: results_add (ticks_get_cached (), s->host, RESULTS_ERROR_NODATA, buffer, header_length); break; default: fprintf (stderr, "%s: internal PCRE in http protocol module\n", opt_program); exit (EXIT_FAILURE); } /* No more pending requests, connection is closed automatically. */ } /* arch-tag: dcaa5f69-6a42-4337-8790-596382a58920 */