43 |
#include <netinet/in.h> |
#include <netinet/in.h> |
44 |
#endif |
#endif |
45 |
|
|
46 |
#ifdef HAVE_ARPA_INET_H |
#include "md5.h" |
47 |
#include <arpa/inet.h> |
#include "sha.h" |
|
#endif |
|
|
|
|
|
#include "../md5.h" |
|
|
#include "../sha.h" |
|
48 |
#include "protocol.h" |
#include "protocol.h" |
49 |
|
|
50 |
|
|
54 |
|
|
55 |
/* Private prototypes */ |
/* Private prototypes */ |
56 |
static int check_request(Socket_T s); |
static int check_request(Socket_T s); |
57 |
static char *get_host_header(Socket_T s, char * host); |
static int check_request_checksum(Socket_T s, char *checksum, int hashtype); |
|
static int check_request_checksum(Socket_T s, char *checksum, int); |
|
58 |
|
|
59 |
|
|
60 |
/** |
/** |
73 |
* |
* |
74 |
* @author Jan-Henrik Haukeland, <hauk@tildeslash.com> |
* @author Jan-Henrik Haukeland, <hauk@tildeslash.com> |
75 |
* @author Martin Pala, <martinp@tildeslash.com> |
* @author Martin Pala, <martinp@tildeslash.com> |
|
* |
|
76 |
* @version \$Id$ |
* @version \$Id$ |
|
* |
|
77 |
* @file |
* @file |
78 |
*/ |
*/ |
79 |
int check_http(Socket_T s) { |
int check_http(Socket_T s) { |
80 |
|
|
81 |
char host[STRLEN]; |
char host[STRLEN]; |
82 |
char *request= NULL; |
char *request= NULL; |
|
char *request_checksum= NULL; |
|
|
int request_hashtype= 0; |
|
83 |
|
|
84 |
ASSERT(s); |
ASSERT(s); |
85 |
|
|
|
if(socket_get_Port(s)) { |
|
|
request= ((Port_T)(socket_get_Port(s)))->request; |
|
|
request_checksum= ((Port_T)(socket_get_Port(s)))->request_checksum; |
|
|
request_hashtype= ((Port_T)(socket_get_Port(s)))->request_hashtype; |
|
|
} |
|
|
|
|
86 |
request= request?request:"/"; |
request= request?request:"/"; |
87 |
|
|
88 |
if(socket_print(s, "GET %s HTTP/1.1\r\n" |
if(socket_print(s, |
89 |
|
"GET %s HTTP/1.1\r\n" |
90 |
"Host: %s\r\n" |
"Host: %s\r\n" |
91 |
"Accept: */*\r\n" |
"Accept: */*\r\n" |
92 |
"User-Agent: %s/%s\r\n" |
"User-Agent: %s/%s\r\n" |
93 |
"Connection: close\r\n\r\n", |
"Connection: close\r\n\r\n", |
94 |
request, get_host_header(s, host), prog, VERSION) < 0) { |
request, Util_getHTTPHostHeader(s, host,STRLEN), |
95 |
|
prog, VERSION) < 0) { |
96 |
log("HTTP: error sending data -- %s\n", STRERROR); |
log("HTTP: error sending data -- %s\n", STRERROR); |
97 |
return FALSE; |
return FALSE; |
98 |
} |
} |
99 |
|
|
|
if(request_checksum) { |
|
|
return check_request_checksum(s, request_checksum, request_hashtype); |
|
|
} |
|
|
|
|
100 |
return check_request(s); |
return check_request(s); |
101 |
|
|
102 |
} |
} |
106 |
|
|
107 |
|
|
108 |
/** |
/** |
|
* @return a "hostname:port" or a void string if host |
|
|
* equals LOCALHOST or if it is an IP address |
|
|
*/ |
|
|
static char *get_host_header(Socket_T s, char *hostbuf) { |
|
|
|
|
|
if(! strcmp(LOCALHOST, socket_get_remote_host(s)) || |
|
|
inet_aton(socket_get_remote_host(s), NULL)) { |
|
|
|
|
|
*hostbuf= 0; |
|
|
|
|
|
} else { |
|
|
|
|
|
snprintf(hostbuf, STRLEN, "%s:%d", |
|
|
socket_get_remote_host(s), |
|
|
socket_get_remote_port(s)); |
|
|
|
|
|
} |
|
|
|
|
|
return hostbuf; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
109 |
* Check that the server returns a valid HTTP response |
* Check that the server returns a valid HTTP response |
110 |
* @param s A socket |
* @param s A socket |
111 |
* @return TRUE if the response is valid otherwise FALSE |
* @return TRUE if the response is valid otherwise FALSE |
115 |
int n; |
int n; |
116 |
int status; |
int status; |
117 |
char buf[STRLEN]; |
char buf[STRLEN]; |
118 |
char msg[STRLEN]; |
Port_T P= (Port_T)socket_get_Port(s); |
119 |
char proto[STRLEN]; |
|
|
|
|
120 |
if(! socket_readln(s, buf, sizeof(buf))) { |
if(! socket_readln(s, buf, sizeof(buf))) { |
121 |
log("HTTP: error receiving data -- %s\n", STRERROR); |
log("HTTP: error receiving data -- %s\n", STRERROR); |
122 |
return FALSE; |
return FALSE; |
123 |
} |
} |
124 |
|
Util_chomp(buf, STRLEN); |
125 |
chomp(buf, STRLEN); |
n= sscanf(buf, "%*s %d", &status); |
126 |
|
if(n!=1 || (status >= 400)) { |
|
/* RATS: ignore */ /* chomp does zero termination */ |
|
|
n= sscanf(buf, "%s %d %s", proto, &status, msg); |
|
|
if(n!=3 || (status >= 400)) { |
|
127 |
log("HTTP error: %s\n", buf); |
log("HTTP error: %s\n", buf); |
128 |
return FALSE; |
return FALSE; |
129 |
} |
} |
130 |
|
|
131 |
|
if(P && P->request_checksum) { |
132 |
|
return check_request_checksum(s, P->request_checksum, P->request_hashtype); |
133 |
|
} |
134 |
|
|
135 |
return TRUE; |
return TRUE; |
136 |
|
|
137 |
} |
} |
143 |
* the response does not contain the Content-Length header, the |
* the response does not contain the Content-Length header, the |
144 |
* checksum is not tested and this method returns TRUE. |
* checksum is not tested and this method returns TRUE. |
145 |
* @param s A socket |
* @param s A socket |
146 |
* @param checksum expected checksum |
* @param checksum Request digest to test |
147 |
|
* @param hashtype The digest type |
148 |
* @return TRUE if the respons is valid and the checksum match, |
* @return TRUE if the respons is valid and the checksum match, |
149 |
* otherwise FALSE |
* otherwise FALSE |
150 |
*/ |
*/ |
154 |
char line[STRLEN]; |
char line[STRLEN]; |
155 |
long content_length= 0; |
long content_length= 0; |
156 |
|
|
|
if(! check_request(s)) |
|
|
return FALSE; |
|
|
|
|
157 |
while(NULL != socket_readln(s, line, STRLEN)) { |
while(NULL != socket_readln(s, line, STRLEN)) { |
158 |
if(starts_with(line, "\r\n") || starts_with(line, "\n")) |
if(Util_startsWith(line, "\r\n") || Util_startsWith(line, "\n")) |
159 |
break; |
break; |
160 |
if(starts_with(line, "Content-Length")) { |
if(Util_startsWith(line, "Content-Length")) { |
|
/* RATS: ignore */ /* socket_readln does zero termination */ |
|
161 |
if(1 != sscanf(line, "%*s%*[: ]%ld", &content_length)) { |
if(1 != sscanf(line, "%*s%*[: ]%ld", &content_length)) { |
162 |
chomp(line, STRLEN); |
Util_chomp(line, STRLEN); |
163 |
log("HTTP error: parsing Content-Length response header '%s'\n", line); |
log("HTTP error: parsing Content-Length response header '%s'\n", line); |
164 |
return FALSE; |
return FALSE; |
165 |
} |
} |
167 |
} |
} |
168 |
|
|
169 |
if(! content_length) { |
if(! content_length) { |
|
|
|
170 |
DEBUG("HTTP warning: Response does not contain Content-Length\n"); |
DEBUG("HTTP warning: Response does not contain Content-Length\n"); |
|
|
|
171 |
} else { |
} else { |
172 |
|
|
173 |
int n; |
int n; |
180 |
|
|
181 |
switch (hashtype) { |
switch (hashtype) { |
182 |
case HASH_MD5: |
case HASH_MD5: |
183 |
{ |
{ |
184 |
struct md5_ctx ctx; |
struct md5_ctx ctx; |
185 |
md5_init_ctx(&ctx); |
md5_init_ctx(&ctx); |
186 |
while(content_length > 0) { |
while(content_length > 0) { |
187 |
size= content_length>READ_SIZE?READ_SIZE:content_length; |
size= content_length>READ_SIZE?READ_SIZE:content_length; |
188 |
n= socket_read(s, buf, size); |
n= socket_read(s, buf, size); |
189 |
if(n<0) break; |
if(n<0) break; |
190 |
md5_process_bytes(buf, n, &ctx); |
md5_process_bytes(buf, n, &ctx); |
191 |
content_length -= n; |
content_length -= n; |
192 |
|
} |
193 |
|
md5_finish_ctx(&ctx, hash); |
194 |
|
keylength=16; /* Raw key bytes not string chars! */ |
195 |
|
break; |
196 |
} |
} |
|
md5_finish_ctx(&ctx, hash); |
|
|
keylength=16; /* Raw key bytes not string chars! */ |
|
|
break; |
|
|
} |
|
197 |
case HASH_SHA1: |
case HASH_SHA1: |
198 |
{ |
{ |
199 |
struct sha_ctx ctx; |
struct sha_ctx ctx; |
200 |
sha_init_ctx(&ctx); |
sha_init_ctx(&ctx); |
201 |
while(content_length > 0) { |
while(content_length > 0) { |
202 |
size= content_length>READ_SIZE?READ_SIZE:content_length; |
size= content_length>READ_SIZE?READ_SIZE:content_length; |
203 |
n= socket_read(s, buf, size); |
n= socket_read(s, buf, size); |
204 |
if(n<0) break; |
if(n<0) break; |
205 |
sha_process_bytes(buf, n, &ctx); |
sha_process_bytes(buf, n, &ctx); |
206 |
content_length -= n; |
content_length -= n; |
207 |
|
} |
208 |
|
sha_finish_ctx(&ctx, hash); |
209 |
|
keylength=20; /* Raw key bytes not string chars! */ |
210 |
|
break; |
211 |
} |
} |
|
sha_finish_ctx(&ctx, hash); |
|
|
keylength=20; /* Raw key bytes not string chars! */ |
|
|
break; |
|
|
} |
|
212 |
default: |
default: |
213 |
DEBUG("HTTP warning: Unknown hash type\n"); |
DEBUG("HTTP warning: Unknown hash type\n"); |
214 |
return FALSE; |
return FALSE; |
215 |
} |
} |
|
|
|
216 |
r= result; |
r= result; |
217 |
for(i= 0; i < keylength; ++i) |
for(i= 0; i < keylength; ++i) { |
218 |
r+= snprintf(r, STRLEN-(r-result) ,"%02x", hash[i]); |
r+= snprintf(r, STRLEN-(r-result) ,"%02x", hash[i]); |
219 |
|
} |
220 |
if(strncasecmp(result, checksum, keylength*2) != 0) { |
if(strncasecmp(result, checksum, keylength*2) != 0) { |
221 |
DEBUG("HTTP warning: Document checksum mismatch\n"); |
DEBUG("HTTP warning: Document checksum mismatch\n"); |
222 |
return FALSE; |
return FALSE; |
223 |
} else { |
} else { |
224 |
DEBUG("HTTP: Succeeded testing document checksum\n"); |
DEBUG("HTTP: Succeeded testing document checksum\n"); |
225 |
} |
} |
|
|
|
226 |
} |
} |
227 |
|
|
228 |
return TRUE; |
return TRUE; |
229 |
|
|
230 |
} |
} |