1 /* doscan - Denial Of Service Capable Auditing of Networks
2  * Copyright (C) 2003 Florian Weimer
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18 
19 /* This is a simple HTTP version string collector, intended as sample
20    code for the TCP engine code. */
21 
22 #include "config.h"
23 #include "engine_tcp.h"
24 #include "opt.h"
25 #include "proto.h"
26 #include "results.h"
27 #include "scan.h"
28 #include "utils.h"
29 
30 #include <cstdio>
31 
32 static bool http_start (subnets&);
33 static void http_open (scan_host_t *);
34 static void http_send_request (scan_host_t *);
35 static void http_receive_reply (scan_host_t *);
36 static void http_finish (scan_host_t *, const char *buffer, unsigned size);
37 
38 static char *request_buffer;
39 static unsigned request_size;
40 
41 static pcre *end_regexp;
42 static pcre *server_regexp;
43 
44 void
proto_http_register(void)45 proto_http_register (void)
46 {
47   proto_register ("http", http_start, http_open);
48 }
49 
50 static bool
http_start(subnets &)51 http_start (subnets&)
52 {
53   const char *errptr;
54   int erroffset;
55 
56   if (opt_banner_size == 0) {
57     opt_banner_size = 4000;
58   }
59 
60   if (opt_send && (opt_send[0] != '\0')) {
61     string_dequote (opt_send, &request_buffer, &request_size, "--send option");
62   } else {
63     string_dequote ("GET / HTTP/1.0\\r\\n\\r\\n",
64                     &request_buffer, &request_size, "--send option");
65   }
66 
67   if (opt_receive && (opt_receive[0] != '\0')) {
68     fprintf (stderr, "%s: http protocol module does not support --receive\n",
69              opt_program);
70     exit (EXIT_FAILURE);
71   }
72 
73   end_regexp
74     = pcre_compile ("(.*?)\r\n\r\n",
75                     PCRE_ANCHORED | PCRE_DOLLAR_ENDONLY | PCRE_DOTALL,
76                     &errptr, &erroffset, 0);
77   server_regexp
78     = pcre_compile (".*\r\nServer:[\t ]*(.*?)[\t ]*\r\n",
79                     PCRE_ANCHORED | PCRE_DOLLAR_ENDONLY | PCRE_DOTALL,
80                     &errptr, &erroffset, 0);
81   if (! (end_regexp && server_regexp)) {
82     fprintf (stderr, "%s: fatal PCRE error\n",
83              opt_program);
84     exit (EXIT_FAILURE);
85   }
86 
87   return true;
88 }
89 
90 static void
http_open(scan_host_t * s)91 http_open (scan_host_t *s)
92 {
93   if (!s->state) {
94     s->state = malloc (sizeof (engine_tcp_t));
95   }
96   engine_tcp_open (s, http_send_request, http_receive_reply);
97 }
98 
99 static void
http_send_request(scan_host_t * s)100 http_send_request (scan_host_t *s)
101 {
102   engine_tcp_send (s, request_buffer, request_size, ENGINE_TCP_NO_COPY,
103                    http_receive_reply);
104 }
105 
106 static void
http_receive_reply(scan_host_t * s)107 http_receive_reply (scan_host_t *s)
108 {
109   engine_tcp_receive_until_match (s, end_regexp, 0, opt_banner_size,
110                                   http_finish);
111 }
112 
113 static void
http_finish(scan_host_t * s,const char * buffer,unsigned size)114 http_finish (scan_host_t *s, const char *buffer, unsigned size)
115 {
116   int ovector[6];
117   int rc;
118   unsigned header_length;
119 
120   /* First determine the end of the header. */
121 
122   rc = pcre_exec (end_regexp, 0, buffer, size, 0, 0, ovector, 6);
123 
124   if (rc != 2) {
125     fprintf (stderr, "%s: internal error %d in http protocol module\n",
126              opt_program, rc);
127     exit (EXIT_FAILURE);
128   }
129   if (ovector[2] != 0) {
130     fprintf (stderr, "%s: internal match error in http protocol module\n",
131              opt_program);
132     exit (EXIT_FAILURE);
133   }
134   header_length = ovector[3];
135 
136   /* Then look for the Server: string in the header. */
137 
138   rc = pcre_exec (server_regexp, 0, buffer, header_length,
139                   0, 0, ovector, 6);
140   switch (rc) {
141   case 2:
142     results_add (ticks_get_cached (), s->host, 0,
143                  buffer + ovector[2], ovector[3] - ovector[2]);
144     break;
145 
146   case PCRE_ERROR_NOMATCH:
147     results_add (ticks_get_cached (), s->host, RESULTS_ERROR_NODATA,
148                  buffer, header_length);
149     break;
150 
151   default:
152     fprintf (stderr, "%s: internal PCRE in http protocol module\n",
153              opt_program);
154     exit (EXIT_FAILURE);
155   }
156 
157   /* No more pending requests, connection is closed automatically. */
158 }
159