1.94b: Proxy support and bugfixes

- Proxy support! Currently only works for HTTP, put behind #ifdef PROXY_SUPPORT.
- Change to prefix() and change_prefix() macros to limit the risk of bugs.
This commit is contained in:
Steve Pinkham 2011-08-09 16:03:29 -04:00
parent e7485cd346
commit b199943c9d
10 changed files with 207 additions and 97 deletions

View File

@ -1,3 +1,11 @@
Version 1.94b:
--------------
- Proxy support! Currently only works for HTTP, put behind #ifdef
PROXY_SUPPORT.
- Change to prefix() and change_prefix() macros to limit the risk of bugs.
Version 1.93b:
--------------

View File

@ -20,7 +20,7 @@
#
PROGNAME = skipfish
VERSION = 1.93b
VERSION = 1.94b
OBJFILES = http_client.c database.c crawler.c analysis.c report.c
INCFILES = alloc-inl.h string-inl.h debug.h types.h http_client.h \

6
README
View File

@ -502,9 +502,9 @@ know:
* More specific PHP tests (eval injection, RFI).
* Proxy support: somewhat incompatible with performance control features
currently employed by skipfish; but in the long run, should be provided
as a last-resort option.
* Proxy support: an experimental HTTP proxy support is available through
a #define directive in config.h. Adding support for HTTPS proxying is
more complicated, and still in the works.
* Scan resume option.

View File

@ -80,7 +80,7 @@ void pivot_header_checks(struct http_request* req,
for (i=0;i<res->hdr.c;i++) {
if (res->hdr.t[i] != PARAM_HEADER ||
strncasecmp((char*)res->hdr.n[i], "X-", 2)) continue;
case_prefix(res->hdr.n[i], "X-")) continue;
if (!RPAR(req)->res) par_hdr = NULL;
else par_hdr = GET_HDR(res->hdr.n[i], &RPAR(req)->res->hdr);
@ -96,7 +96,7 @@ void pivot_header_checks(struct http_request* req,
for (i=0;i<RPAR(req)->res->hdr.c;i++) {
if (RPAR(req)->res->hdr.t[i] != PARAM_HEADER ||
strncasecmp((char*)RPAR(req)->res->hdr.n[i], "X-", 2)) continue;
case_prefix(RPAR(req)->res->hdr.n[i], "X-")) continue;
cur_hdr = GET_HDR(RPAR(req)->res->hdr.n[i], &res->hdr);
@ -122,10 +122,10 @@ static void test_add_link(u8* str, struct http_request* ref,
/* Don't add injected links. */
if (!strncasecmp((char*)str, "skipfish:", 9) ||
!strncasecmp((char*)str, "//skipfish.invalid/", 19) ||
if (!case_prefix(str, "skipfish:") ||
!case_prefix(str, "//skipfish.invalid/") ||
inl_strcasestr(str, (u8*) "/" BOGUS_FILE) ||
!strncasecmp((char*)str, "http://skipfish.invalid/", 24)) return;
!case_prefix(str, "http://skipfish.invalid/")) return;
/* Don't add links that look like they came from JS code with fragmented HTML
snippets, etc. */
@ -136,7 +136,7 @@ static void test_add_link(u8* str, struct http_request* ref,
if ((str[0] == '\'' || str[0] == '"') && (str[1] == '+' || str[1] == ' '))
return;
if (!strncasecmp((char*)str, "mailto:", 7)) {
if (!case_prefix(str, "mailto:")) {
if (log_ext_urls) {
u8* qmark = (u8*)strchr((char*)str, '?');
@ -262,19 +262,19 @@ static u8* html_decode_param(u8* url, u8 also_js) {
if (url[i] == '&') {
if (!strncasecmp((char*)url + i + 1, "amp;", 4)) {
if (!case_prefix(url + i + 1, "amp;")) {
ret[pos++] = '&';
i += 4;
continue;
} else if (!strncasecmp((char*)url + i + 1, "quot;", 5)) {
} else if (!case_prefix(url + i + 1, "quot;")) {
ret[pos++] = '\'';
i += 5;
continue;
} else if (!strncasecmp((char*)url + i + 1, "lt;", 3)) {
} else if (!case_prefix(url + i + 1, "lt;")) {
ret[pos++] = '<';
i += 3;
continue;
} else if (!strncasecmp((char*)url + i + 1, "gt;", 3)) {
} else if (!case_prefix(url + i + 1, "gt;")) {
ret[pos++] = '>';
i += 3;
continue;
@ -398,8 +398,7 @@ static u8 maybe_xsrf(u8* token) {
/* Unix time is not a valid token. */
if (!strncasecmp((char*)token, (char*)tm_prefix, strlen((char*)tm_prefix)))
return 0;
if (!case_prefix(token, tm_prefix)) return 0;
tmp = token;
while (*tmp && (isdigit(*tmp) || strchr("abcdef", tolower(*tmp)))) {
@ -464,7 +463,7 @@ static void collect_form_data(struct http_request* req,
cur_str++;
*tag_end = 0;
if (!strncasecmp((char*)cur_str, "/form", 5)) {
if (!case_prefix(cur_str, "/form")) {
*tag_end = '>';
goto final_checks;
}
@ -909,8 +908,7 @@ next_tag:
We do not make assumptins about syntax such as /foo/, though, as
it could very well be a regex in a JS block. */
if (!strncmp((char*)clean_url, "./", 2) || !strncmp((char*)clean_url,
"../", 3)) {
if (!prefix(clean_url, "./") || !prefix(clean_url, "../")) {
add_link:
test_add_link(clean_url, base ? base : req, res, 0, 0);
goto url_done;
@ -921,7 +919,7 @@ add_link:
while (clean_url[lead] && (isalnum(clean_url[lead]))) lead++;
if (lead && !strncmp((char*)clean_url + lead, "://", 3) &&
if (lead && !prefix(clean_url + lead, "://") &&
clean_url[lead + 3]) goto add_link;
/* URL CHECK 3: If the result ends with <str>.<known_ext>,
@ -1047,7 +1045,7 @@ static u8 is_css(struct http_response* res) {
/* Skip HTML, CSS comments. */
if (!strncmp((char*)text, "<!--", 4)) {
if (!prefix(text, "<!--")) {
text += 4;
continue;
}
@ -1072,9 +1070,9 @@ static u8 is_css(struct http_response* res) {
/* @import, @media, or @charset is a clear indicator of CSS. */
if (*text == '@' && (!strncasecmp((char*)text + 1, "import", 6) ||
!strncasecmp((char*)text + 1, "media", 5) ||
!strncasecmp((char*)text + 1, "charset", 7))) {
if (*text == '@' && (!case_prefix(text + 1, "import") ||
!case_prefix(text + 1, "media") ||
!case_prefix(text + 1, "charset"))) {
res->css_type = 2;
return 1;
}
@ -1157,11 +1155,11 @@ static u8 is_javascript(struct http_response* res) {
/* Skip HTML, JS comments. Special case for MOTW. */
if (!strncmp((char*)text, "<!--", 4)) {
if (!prefix(text, "<!--")) {
text += 4;
if (!strncmp((char*)text, " saved from url=", 16)) {
if (!prefix(text, " saved from url=")) {
res->js_type = 1;
return 0;
}
@ -1194,7 +1192,7 @@ static u8 is_javascript(struct http_response* res) {
if (!first)
while (json_safe[i]) {
if (!strncasecmp((char*)text, json_safe[i], strlen(json_safe[i]))) {
if (!case_prefix(text, json_safe[i])) {
res->js_type = 2;
res->json_safe = 1;
return 1;
@ -1270,20 +1268,20 @@ static void check_js_xss(struct http_request* req, struct http_response* res,
and current string starts with //skipfishy thingees,
complain. */
if ((!strncmp((char*)last_word, "innerHTML", 9) ||
!strncmp((char*)last_word, "open", 4) ||
!strncmp((char*)last_word, "url", 3) ||
!strncmp((char*)last_word, "href", 4) ||
!strncmp((char*)last_word, "write", 5)) &&
(!strncasecmp((char*)text + 1,"//skipfish.invalid/", 19) ||
!strncasecmp((char*)text + 1,"http://skipfish.invalid/", 24) ||
!strncasecmp((char*)text + 1,"skipfish:", 9)))
if ((!prefix(last_word, "innerHTML") ||
!prefix(last_word, "open") ||
!prefix(last_word, "url") ||
!prefix(last_word, "href") ||
!prefix(last_word, "write")) &&
(!case_prefix(text + 1,"//skipfish.invalid/") ||
!case_prefix(text + 1,"http://skipfish.invalid/") ||
!case_prefix(text + 1,"skipfish:")))
problem(PROB_URL_XSS, req, res,
(u8*)"injected URL in JS/CSS code", req->pivot, 0);
} else if (in_quot && *text == in_quot) in_quot = 0;
else if (!in_quot && !strncasecmp((char*)text, "sfi", 3) &&
else if (!in_quot && !case_prefix(text, "sfi") &&
sscanf((char*)text, "sfi%06uv%06u", &tag_id, &scan_id) == 2) {
struct http_request* orig = get_xss_request(tag_id, scan_id);
@ -1576,7 +1574,7 @@ void content_checks(struct http_request* req, struct http_response* res) {
/* Skip comments where possible. */
if (!strncmp((char*)tmp, "!--", 3)) {
if (!prefix(tmp, "!--")) {
u8* next = (u8*)strstr((char*)tmp + 3, "-->");
if (next) {
tmp = next + 3;
@ -1644,7 +1642,7 @@ void content_checks(struct http_request* req, struct http_response* res) {
strcasecmp((char*)tag_name, "input")) ||
!strcasecmp((char*)param_name, "codebase")) && clean_val) {
if (!strncasecmp((char*)clean_val, "skipfish://", 11))
if (!case_prefix(clean_val, "skipfish:"))
problem(PROB_URL_XSS, req, res, tag_name, req->pivot, 0);
/* A bit hairy, but in essence, links to attacker-supplied
@ -1652,8 +1650,8 @@ void content_checks(struct http_request* req, struct http_response* res) {
are sorta noteworthy, depending on context; and A links
are usually of little relevance. */
if (!strncasecmp((char*)clean_val, "http://skipfish.invalid/", 24) ||
!strncasecmp((char*)clean_val, "//skipfish.invalid/", 19)) {
if (!case_prefix(clean_val, "http://skipfish.invalid/") ||
!case_prefix(clean_val, "//skipfish.invalid/")) {
if (!strcasecmp((char*)tag_name, "script") ||
!strcasecmp((char*)tag_name, "link"))
@ -1679,14 +1677,14 @@ void content_checks(struct http_request* req, struct http_response* res) {
url += 4;
if (*url == '\'' || *url == '"') { url++; semi_safe = 1; }
if (!strncasecmp((char*)url, "http://skipfish.invalid/", 24) ||
!strncasecmp((char*)url, "//skipfish.invalid/", 19))
if (!case_prefix(url, "http://skipfish.invalid/") ||
!case_prefix(url, "//skipfish.invalid/"))
problem(PROB_URL_REDIR, req, res, (u8*)"injected URL in META refresh",
req->pivot, 0);
/* Unescaped semicolon in Refresh headers is unsafe with MSIE6. */
if (!strncasecmp((char*)url, "skipfish://", 11) ||
if (!case_prefix(url, "skipfish:") ||
(!semi_safe && strchr((char*)url, ';')))
problem(PROB_URL_XSS, req, res, (u8*)"injected URL in META refresh",
req->pivot, 0);
@ -1705,7 +1703,7 @@ void content_checks(struct http_request* req, struct http_response* res) {
/* CHECK 3.3: JavaScript on*=, CSS style= parameters. */
if ((!strncasecmp((char*)param_name, "on", 2) ||
if ((!case_prefix(param_name, "on") ||
!strcasecmp((char*)param_name, "style")) && clean_val)
check_js_xss(req, res, clean_val);
@ -1941,19 +1939,19 @@ static void detect_mime(struct http_request* req, struct http_response* res) {
}
if (!strncmp((char*)sniffbuf, "%!PS", 4)) {
if (!prefix(sniffbuf, "%!PS")) {
res->sniff_mime_id = MIME_ASC_POSTSCRIPT;
return;
}
if (!strncmp((char*)sniffbuf, "{\\rtf", 5)) {
if (!prefix(sniffbuf, "{\\rtf")) {
res->sniff_mime_id = MIME_ASC_RTF;
return;
}
/* Adobe PDF (may be mostly ASCII in some cases). */
if (!strncmp((char*)sniffbuf, "%PDF", 4)) {
if (!prefix(sniffbuf, "%PDF")) {
res->sniff_mime_id = MIME_EXT_PDF;
return;
}
@ -2058,29 +2056,29 @@ static void detect_mime(struct http_request* req, struct http_response* res) {
return;
}
if (!strncmp((char*)sniffbuf, "GIF8", 4)) {
if (!prefix(sniffbuf, "GIF8")) {
res->sniff_mime_id = MIME_IMG_GIF;
return;
}
if (sniffbuf[0] == 0x89 && !strncmp((char*)sniffbuf + 1, "PNG", 3)) {
if (sniffbuf[0] == 0x89 && !prefix(sniffbuf + 1, "PNG")) {
res->sniff_mime_id = MIME_IMG_PNG;
return;
}
if (!strncmp((char*)sniffbuf, "BM", 2)) {
if (!prefix(sniffbuf, "BM")) {
res->sniff_mime_id = MIME_IMG_BMP;
return;
}
if (!strncmp((char*)sniffbuf, "II", 2) && sniffbuf[2] == 42 /* dec */) {
if (!prefix(sniffbuf, "II") && sniffbuf[2] == 42 /* dec */) {
res->sniff_mime_id = MIME_IMG_TIFF;
return;
}
/* Next: RIFF containers (AVI, ANI, WAV). */
if (!strncmp((char*)sniffbuf, "RIFF", 4)) {
if (!prefix(sniffbuf, "RIFF")) {
if (sniffbuf[8] == 'A') {
if (sniffbuf[9] == 'C')
@ -2123,27 +2121,27 @@ static void detect_mime(struct http_request* req, struct http_response* res) {
return;
}
if (!strncasecmp((char*)sniffbuf, "OggS", 4)) {
if (!prefix(sniffbuf, "OggS")) {
res->sniff_mime_id = MIME_AV_OGG;
return;
}
if (sniffbuf[0] == 0x28 && !strncasecmp((char*)sniffbuf + 1, "RMF", 3)) {
if (sniffbuf[0] == 0x28 && !prefix(sniffbuf + 1, "RMF")) {
res->sniff_mime_id = MIME_AV_RA;
return;
}
if (sniffbuf[0] == 0x2E && !strncasecmp((char*)sniffbuf + 1, "RMF", 3)) {
if (sniffbuf[0] == 0x2E && !prefix(sniffbuf + 1, "RMF")) {
res->sniff_mime_id = MIME_AV_RV;
return;
}
if (!strncmp((char*)sniffbuf + 4, "free", 4) ||
!strncmp((char*)sniffbuf + 4, "mdat", 4) ||
!strncmp((char*)sniffbuf + 4, "wide", 4) ||
!strncmp((char*)sniffbuf + 4, "pnot", 4) ||
!strncmp((char*)sniffbuf + 4, "skip", 4) ||
!strncmp((char*)sniffbuf + 4, "moov", 4)) {
if (!prefix(sniffbuf + 4, "free") ||
!prefix(sniffbuf + 4, "mdat") ||
!prefix(sniffbuf + 4, "wide") ||
!prefix(sniffbuf + 4, "pnot") ||
!prefix(sniffbuf + 4, "skip") ||
!prefix(sniffbuf + 4, "moov")) {
/* Oookay, that was weird... */
res->sniff_mime_id = MIME_AV_QT;
return;
@ -2151,20 +2149,20 @@ static void detect_mime(struct http_request* req, struct http_response* res) {
/* Flash and FLV. */
if (!strncmp((char*)sniffbuf, "FLV", 3)) {
if (!prefix(sniffbuf, "FLV")) {
res->sniff_mime_id = MIME_AV_FLV;
return;
}
if (!strncmp((char*)sniffbuf, "FCWS", 4) ||
!strncmp((char*)sniffbuf, "CWS", 3)) {
if (!prefix(sniffbuf, "FCWS") ||
!prefix(sniffbuf, "CWS")) {
res->sniff_mime_id = MIME_EXT_FLASH;
return;
}
/* Adobe PDF. */
if (!strncmp((char*)sniffbuf, "%PDF", 4)) {
if (!prefix(sniffbuf, "%PDF")) {
res->sniff_mime_id = MIME_EXT_PDF;
return;
}
@ -2172,7 +2170,7 @@ static void detect_mime(struct http_request* req, struct http_response* res) {
/* JAR versus ZIP. A bit tricky, because, well, they are both just
ZIP archives. */
if (!strncmp((char*)sniffbuf, "PK", 2) &&
if (!prefix(sniffbuf, "PK") &&
sniffbuf[2] < 6 && sniffbuf[3] < 7) {
if (inl_memmem(res->payload, res->pay_len, "META-INF/", 9))
@ -2429,7 +2427,7 @@ static void check_for_stuff(struct http_request* req,
/* This should also cover most cases of Perl, Python, etc. */
if (!strncmp((char*)sniffbuf, "#!/", 3)) {
if (!prefix(sniffbuf, "#!/")) {
problem(PROB_FILE_POI, req, res, (u8*)"shell script", req->pivot, 0);
return;
}

View File

@ -27,6 +27,12 @@
#define SHOW_SPLASH 1 /* Annoy user with a splash screen */
/* Define this to enable experimental HTTP proxy support, through the -J
option in the command line. This mode will not work as expected for
HTTPS requests at this point. */
// #define PROXY_SUPPORT 1
/* Default paths to runtime files: */
#define ASSETS_DIR "assets"

View File

@ -980,12 +980,12 @@ static u8 inject_check5_callback(struct http_request* req,
if (val) {
if (!strncasecmp((char*)val, "http://skipfish.invalid/", 24) ||
!strncasecmp((char*)val, "//skipfish.invalid/", 19))
if (!case_prefix(val, "http://skipfish.invalid/") ||
!case_prefix(val, "//skipfish.invalid/"))
problem(PROB_URL_REDIR, req, res, (u8*)"injected URL in 'Location' header",
req->pivot, 0);
if (!strncasecmp((char*)val, "skipfish://", 11))
if (!case_prefix(val, "skipfish:"))
problem(PROB_URL_XSS, req, res, (u8*)"injected URL in 'Location' header",
req->pivot, 0);
@ -998,14 +998,14 @@ static u8 inject_check5_callback(struct http_request* req,
if (*val == '\'' || *val == '"') { val++; semi_safe++; }
if (!strncasecmp((char*)val, "http://skipfish.invalid/", 24) ||
!strncasecmp((char*)val, "//skipfish.invalid/", 19))
if (!case_prefix(val, "http://skipfish.invalid/") ||
!case_prefix(val, "//skipfish.invalid/"))
problem(PROB_URL_REDIR, req, res, (u8*)"injected URL in 'Refresh' header",
req->pivot, 0);
/* Unescaped semicolon in Refresh headers is unsafe with MSIE6. */
if (!strncasecmp((char*)val, "skipfish://", 11) ||
if (!case_prefix(val, "skipfish:") ||
(!semi_safe && strchr((char*)val, ';')))
problem(PROB_URL_XSS, req, res, (u8*)"injected URL in 'Refresh' header",
req->pivot, 0);
@ -2821,7 +2821,7 @@ static u8 dir_dict_callback(struct http_request* req,
/* Do not add 403 responses to .ht* requests - workaround for
Apache filtering to keep reports clean. */
if (lp && !strncmp((char*)lp,".ht",3))
if (lp && !prefix(lp, ".ht"))
i = ~req->pivot->r404_cnt;
/* If not 404, do response, and does not look like

View File

@ -86,6 +86,12 @@ u64 bytes_sent,
u8 *auth_user,
*auth_pass;
#ifdef PROXY_SUPPORT
u8* use_proxy;
u32 use_proxy_addr;
u16 use_proxy_port;
#endif /* PROXY_SUPPORT */
u8 ignore_cookies;
/* Internal globals for queue management: */
@ -187,10 +193,10 @@ u8 parse_url(u8* url, struct http_request* req, struct http_request* ref) {
if (maybe_proto && url[maybe_proto] == ':') {
if (!strncasecmp((char*)url, "http:", 5)) {
if (!case_prefix(url, "http:")) {
req->proto = PROTO_HTTP;
cur += 5;
} else if (!strncasecmp((char*)url, "https:", 6)) {
} else if (!case_prefix(url, "https:")) {
req->proto = PROTO_HTTPS;
cur += 6;
} else return 1;
@ -509,12 +515,12 @@ void tokenize_path(u8* str, struct http_request* req, u8 add_slash) {
probes. This is to avoid recursion if it actually worked in some
way. */
if (!strncmp((char*)cur, "/\\.\\", 4) && (cur[4] == '/' || !cur[4])) {
if (!prefix(cur, "/\\.\\") && (cur[4] == '/' || !cur[4])) {
cur += 4;
continue;
}
if (!strncasecmp((char*)cur, "/%5c.%5c", 8) &&
if (!case_prefix(cur, "/%5c.%5c") &&
(cur[8] == '/' || !cur[8])) {
cur += 8;
continue;
@ -758,6 +764,39 @@ u32 maybe_lookup_host(u8* name) {
u32 ret_addr = 0;
struct in_addr in;
#ifdef PROXY_SUPPORT
/* If configured to use proxy, look up proxy IP once; and return that
address for all host names. */
if (use_proxy) {
if (!use_proxy_addr) {
/* Don't bother resolving raw IP addresses, naturally. */
if (inet_aton((char*)use_proxy, &in))
return (use_proxy_addr = (u32)in.s_addr);
h = gethostbyname((char*)use_proxy);
/* If lookup fails with a transient error, be nice - try again. */
if (!h && h_errno == TRY_AGAIN) h = gethostbyname((char*)name);
if (!h || !(use_proxy_addr = *(u32*)h->h_addr_list[0]))
FATAL("Unable to resolve proxy host name '%s'.", use_proxy);
}
return use_proxy_addr;
}
/* If no proxy... */
#endif /* PROXY_SUPPORT */
/* Don't bother resolving raw IP addresses, naturally. */
if (inet_aton((char*)name, &in))
@ -848,6 +887,25 @@ u8* build_request_data(struct http_request* req) {
if (req->method) ASD(req->method); else ASD((u8*)"GET");
ASD(" ");
#ifdef PROXY_SUPPORT
/* For non-CONNECT proxy requests, insert http://host[:port] too. */
if (use_proxy && req->proto == PROTO_HTTP) {
ASD("http://");
ASD(req->host);
if (req->port != 80) {
char port[7];
sprintf((char*)port, ":%u", req->port);
ASD(port);
}
}
#endif /* PROXY_SUPPORT */
ASD(path);
ASD(" HTTP/1.1\r\n");
ck_free(path);
@ -927,7 +985,6 @@ u8* build_request_data(struct http_request* req) {
}
/* Request a limited range up front to minimize unwanted traffic.
Note that some Oracle servers apparently fail on certain ranged
requests, so allowing -H override seems like a good idea. */
@ -1224,7 +1281,7 @@ u8 parse_response(struct http_request* req, struct http_response* res,
return 1;
}
if (strncmp((char*)cur_line, "HTTP/1.", 7)) {
if (prefix(cur_line, "HTTP/1.")) {
ck_free(cur_line);
return 2;
}
@ -1248,7 +1305,7 @@ u8 parse_response(struct http_request* req, struct http_response* res,
if (!cur_line[0]) break;
if (!strncasecmp((char*)cur_line, "Content-Length:", 15)) {
if (!case_prefix(cur_line, "Content-Length:")) {
/* The value in Content-Length header would be useful for seeing if we
have all the requested data already. Reject invalid values to avoid
@ -1261,7 +1318,7 @@ u8 parse_response(struct http_request* req, struct http_response* res,
}
} else pay_len = -1;
} else if (!strncasecmp((char*)cur_line, "Transfer-Encoding:", 18)) {
} else if (!case_prefix(cur_line, "Transfer-Encoding:")) {
/* Transfer-Encoding: chunked must be accounted for to properly
determine if we received all the data when Content-Length not found. */
@ -1271,7 +1328,7 @@ u8 parse_response(struct http_request* req, struct http_response* res,
while (isspace(*x)) x++;
if (!strcasecmp((char*)x, "chunked")) chunked = 1;
} else if (!strncasecmp((char*)cur_line, "Content-Encoding:", 17)) {
} else if (!case_prefix(cur_line, "Content-Encoding:")) {
/* Content-Encoding is good to know, too. */
@ -1282,7 +1339,7 @@ u8 parse_response(struct http_request* req, struct http_response* res,
if (!strcasecmp((char*)x, "deflate") || !strcasecmp((char*)x, "gzip"))
compressed = 1;
} else if (!strncasecmp((char*)cur_line, "Connection:", 11)) {
} else if (!case_prefix(cur_line, "Connection:")) {
u8* x = cur_line + 11;
@ -1887,7 +1944,12 @@ connect_error:
}
sin.sin_family = PF_INET;
#ifdef PROXY_SUPPORT
sin.sin_port = htons(use_proxy ? use_proxy_port : c->port);
#else
sin.sin_port = htons(c->port);
#endif /* ^PROXY_SUPPORT */
memcpy(&sin.sin_addr, &q->req->addr, 4);
@ -2053,7 +2115,6 @@ SSL_read_more:
c->SSL_rd_w_wr = 0;
read_res = SSL_read(c->srv_ssl, c->read_buf + c->read_len,
READ_CHUNK);

View File

@ -405,6 +405,12 @@ extern u8 auth_type;
extern u8 *auth_user,
*auth_pass;
#ifdef PROXY_SUPPORT
extern u8* use_proxy;
extern u32 use_proxy_addr;
extern u16 use_proxy_port;
#endif /* PROXY_SUPPORT */
/* Global HTTP cookies, extra headers: */
extern struct param_array global_http_par;

View File

@ -77,6 +77,9 @@ static void usage(char* argv0) {
" -C name=val - append a custom cookie to all requests\n"
" -H name=val - append a custom HTTP header to all requests\n"
" -b (i|f|p) - use headers consistent with MSIE / Firefox / iPhone\n"
#ifdef PROXY_SUPPORT
" -J proxy - use a specified HTTP proxy server\n"
#endif /* PROXY_SUPPORT */
" -N - do not accept any new cookies\n\n"
"Crawl scope options:\n\n"
@ -234,7 +237,8 @@ static void read_urls(u8* fn) {
int main(int argc, char** argv) {
s32 opt;
u32 loop_cnt = 0, purge_age = 0, seed;
u8 dont_save_words = 0, show_once = 0, be_quiet = 0, display_mode = 0;
u8 dont_save_words = 0, show_once = 0, be_quiet = 0, display_mode = 0,
has_fake = 0;
u8 *wordlist = (u8*)DEF_WORDLIST, *output_dir = NULL;
struct termios term;
@ -254,7 +258,7 @@ int main(int argc, char** argv) {
SAY("skipfish version " VERSION " by <lcamtuf@google.com>\n");
while ((opt = getopt(argc, argv,
"+A:F:C:H:b:Nd:c:x:r:p:I:X:D:POYQMZUEK:W:LVT:G:R:B:q:g:m:f:t:w:i:s:o:hue")) > 0)
"+A:F:C:H:b:Nd:c:x:r:p:I:X:D:POYQMZUEK:W:LVT:J:G:R:B:q:g:m:f:t:w:i:s:o:hue")) > 0)
switch (opt) {
@ -268,6 +272,18 @@ int main(int argc, char** argv) {
break;
}
#ifdef PROXY_SUPPORT
case 'J': {
u8* x = (u8*)strchr(optarg, ':');
if (!x) FATAL("Proxy data must be in 'host:port' form.");
*(x++) = 0;
use_proxy = (u8*)optarg;
use_proxy_port = atoi((char*)x);
if (!use_proxy_port) FATAL("Incorrect proxy port number.");
break;
}
#endif /* PROXY_SUPPORT */
case 'F': {
u8* x = (u8*)strchr(optarg, '=');
u32 fake_addr;
@ -277,6 +293,7 @@ int main(int argc, char** argv) {
if (fake_addr == (u32)-1)
FATAL("Could not parse IP address '%s'.", x + 1);
fake_host((u8*)optarg, fake_addr);
has_fake = 1;
break;
}
@ -487,6 +504,11 @@ int main(int argc, char** argv) {
}
#ifdef PROXY_SUPPORT
if (has_fake && use_proxy)
FATAL("-F and -J should not be used together.");
#endif /* PROXY_SUPPORT */
if (access(ASSETS_DIR "/index.html", R_OK))
PFATAL("Unable to access '%s/index.html' - wrong directory?", ASSETS_DIR);

View File

@ -51,6 +51,15 @@
#include "types.h"
/* Macros for easy string prefix matching */
#define prefix(_long, _short) \
strncmp((char*)(_long), (char*)(_short), strlen((char*)(_short)))
#define case_prefix(_long, _short) \
strncasecmp((char*)(_long), (char*)(_short), strlen((char*)(_short)))
/* Modified NetBSD strcasestr() implementation (rolling strncasecmp). */
static inline u8* inl_strcasestr(const u8* haystack, const u8* needle) {