home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Freelog 24
/
Freelog024.iso
/
Popup
/
Junkbuster
/
parsers.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-10-30
|
12KB
|
640 lines
char *parsers_rcs = "$Id: parsers.c,v 1.26 1998/10/23 01:54:12 ACJC Exp $";
/* Written and copyright 1997 Anonymous Coders and Junkbusters Corporation.
* Distributed under the GNU General Public License; see the README file.
* This code comes with NO WARRANTY. http://www.junkbusters.com/ht/en/gpl.html
*/
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#ifdef REGEX
#include <gnu_regex.h>
#endif
#include "jcc.h"
struct parsers client_patterns[] = {
{ "referer:", /* sic */ 8, client_referrer },
{ "user-agent:", 11, client_uagent },
{ "ua-", 3, client_ua },
{ "from:", 5, client_from },
{ "cookie:", 7, client_send_cookie },
{ "x-forwarded-for:", 16, client_x_forwarded },
{ "proxy-connection:", 17, crumble },
/* { "if-modified-since:", 18, crumble }, */
{ NULL, 0, NULL }
};
struct interceptors intercept_patterns[] = {
{ "show-proxy-args", 14, show_proxy_args },
{ "ij-blocked-url", 14, ij_blocked_url },
{ "ij-untrusted-url", 14, ij_untrusted_url },
{ NULL, 0, NULL }
};
struct parsers server_patterns[] = {
{ "set-cookie:", 11, server_set_cookie },
{ "connection:", 11, crumble },
{ NULL, 0, NULL }
};
void (*add_client_headers[])() = {
client_cookie_adder,
client_x_forwarded_adder,
client_xtra_adder,
NULL
};
void (*add_server_headers[])() = {
NULL
};
struct parsers *
match(char *buf, struct parsers *pats)
{
struct parsers *v;
if(buf == NULL) {
/* hit me */
fprintf(logfp, "bingo!\n");
return(NULL);
}
for(v = pats; v->str ; v++) {
if(strncmpic(buf, v->str, v->len) == 0) {
return(v);
}
}
return(NULL);
}
int
flush_socket(int fd, struct client_state *csp)
{
struct iob *iob = csp->iob;
int n = iob->eod - iob->cur;
if(n <= 0) return(0);
n = write_socket(fd, iob->cur, n);
iob->eod = iob->cur = iob->buf;
return(n);
}
int
add_to_iob(struct client_state *csp, char *buf, int n)
{
struct iob *iob = csp->iob;
int have, need;
char *p;
have = iob->eod - iob->cur;
if(n <= 0) return(have);
need = have + n;
if((p = malloc(need + 1)) == NULL) {
fprintf(logfp, "%s: malloc() iob failed\n", prog);
fperror(logfp, "");
return(-1);
}
if(have) {
/* there is something in the buffer - save it */
memcpy(p, iob->cur, have);
/* replace the buffer with the new space */
freez(iob->buf);
iob->buf = p;
/* point to the end of the data */
p += have;
} else {
/* the buffer is empty, free it and reinitialize */
freez(iob->buf);
iob->buf = p;
}
/* copy the new data into the iob buffer */
memcpy(p, buf, n);
/* point to the end of the data */
p += n ;
/* null terminate == cheap insurance */
*p = '\0';
/* set the pointers to the new values */
iob->cur = iob->buf;
iob->eod = p;
return(need);
}
/* this (odd) routine will parse the csp->iob and return one of the following:
*
* 1) a pointer to a dynamically allocated string that contains a header line
* 2) NULL indicating that the end of the header was reached
* 3) "" indicating that the end of the iob was reached before finding
* a complete header line.
*/
char *
get_header(struct client_state *csp)
{
struct iob *iob = csp->iob;
char *p, *q, *ret;
if((iob->cur == NULL)
|| ((p = strchr(iob->cur, '\n')) == NULL)) {
return(""); /* couldn't find a complete header */
}
*p = '\0';
ret = strdup(iob->cur);
iob->cur = p+1;
if((q = strchr(ret, '\r'))) *q = '\0';
/* is this a blank linke (i.e. the end of the header) ? */
if(*ret == '\0') {
freez(ret);
return(NULL);
}
return(ret);
}
/* h = pointer to list 'dummy' header
* s = string to add to the list
*/
void
enlist(struct list *h, char *s)
{
struct list *n = (struct list *)malloc(sizeof(*n));
struct list *l;
if(n) {
n->str = strdup(s);
n->next = NULL;
if((l = h->last)) {
l->next = n;
} else {
h->next = n;
}
h->last = n;
}
}
void
destroy_list(struct list *h)
{
struct list *p, *n;
for(p = h->next; p ; p = n) {
n = p->next;
freez(p->str);
freez(p);
}
memset(h, '\0', sizeof(*h));
}
char *
list_to_text(struct list *h)
{
struct list *p;
char *ret = NULL;
char *s;
int size;
size = 0;
for(p = h->next; p ; p = p->next) {
if(p->str) {
size += strlen(p->str) + 2;
}
}
if((ret = malloc(size + 1)) == NULL) {
return(NULL);
}
ret[size] = '\0';
s = ret;
for(p = h->next; p ; p = p->next) {
if(p->str) {
strcpy(s, p->str);
s += strlen(s);
*s++ = '\r'; *s++ = '\n';
}
}
return(ret);
}
/* sed(): add, delete or modify lines in the HTTP header streams.
* on entry, it receives a linked list of headers space that was
* allocated dynamically (both the list nodes and the header contents).
*
* it returns a single pointer to a fully formed header.
*
* as a side effect it frees the space used by the original header lines.
*
*/
char *
sed(pats, more_headers, csp)
struct parsers pats[];
int (*more_headers[])();
struct client_state *csp;
{
struct list *p;
struct parsers *v;
char *hdr;
int (**f)();
for(p = csp->headers->next; p ; p = p->next) {
if(DEBUG(HDR)) fprintf(logfp, "scan: %s", p->str);
if((v = match(p->str, pats))) {
hdr = v->parser(v, p->str, csp);
freez(p->str);
p->str = hdr;
}
if(DEBUG(HDR)) fprintf(logfp, "\n");
}
/* place any additional headers on the csp->headers list */
for(f = more_headers; *f ; f++) {
(*f)(csp);
}
/* add the blank line at the end of the header */
enlist(csp->headers, "");
hdr = list_to_text(csp->headers);
return(hdr);
}
void
free_http_request(struct http_request *http)
{
freez(http->cmd);
freez(http->gpc);
freez(http->host);
freez(http->hostport);
freez(http->path);
freez(http->ver);
}
/* parse out the host and port from the URL */
void
parse_http_request(char *req, struct http_request *http, struct client_state *csp)
{
char *buf, *v[10], *url, *p;
int n;
memset(http, '\0', sizeof(*http));
http->cmd = strdup(req);
buf = strdup(req);
n = ssplit(buf, " \r\n", v, SZ(v), 1, 1);
if(n == 3) {
/* this could be a CONNECT request */
if(strcmpic(v[0], "connect") == 0) {
http->ssl = 1;
http->gpc = strdup(v[0]);
http->hostport = strdup(v[1]);
http->ver = strdup(v[2]);
}
/* or it could be a GET or a POST */
if((strcmpic(v[0], "get") == 0)
|| (strcmpic(v[0], "head") == 0)
|| (strcmpic(v[0], "post") == 0)) {
http->ssl = 0;
http->gpc = strdup(v[0]);
url = v[1] ;
http->ver = strdup(v[2]);
if(strncmpic(url, "http://", 7) == 0) {
url += 7;
} else if(strncmpic(url, "https://", 8) == 0) {
url += 8;
} else {
url = NULL;
}
if(url && (p = strchr(url, '/'))) {
http->path = strdup(p);
*p = '\0';
http->hostport = strdup(url);
}
}
}
freez(buf);
if(http->hostport == NULL) {
free_http_request(http);
return;
}
buf = strdup(http->hostport);
n = ssplit(buf, ":", v, SZ(v), 1, 1);
if(n == 1) {
http->host = strdup(v[0]);
http->port = 80;
}
if(n == 2) {
http->host = strdup(v[0]);
http->port = atoi(v[1]);
}
freez(buf);
if(http->host == NULL) {
free_http_request(http);
}
if(http->path == NULL) {
http->path = strdup("");
}
}
/* here begins the family of parser functions that reformat header lines */
char *crumble(struct parsers *v, char *s, struct client_state *csp)
{
if(DEBUG(HDR)) fprintf(logfp, " crunch!");
return(NULL);
}
char *client_referrer(struct parsers *v, char *s, struct client_state *csp)
{
csp->referrer = strdup(s);
if(referrer == NULL) {
if(DEBUG(HDR)) fprintf(logfp, " crunch!");
return(NULL);
}
if(*referrer == '.') {
return(strdup(s));
}
if(*referrer == '@') {
if(csp->send_user_cookie) {
return(strdup(s));
} else {
if(DEBUG(HDR)) fprintf(logfp, " crunch!");
return(NULL);
}
}
if(DEBUG(HDR)) fprintf(logfp, " modified");
s = strsav(NULL, "Referer: ");
s = strsav(s, referrer );
return(s);
}
char *client_uagent(struct parsers *v, char *s, struct client_state *csp)
{
if(uagent == NULL) {
if(DEBUG(HDR)) fprintf(logfp, " default");
return(strdup(DEFAULT_USER_AGENT));
}
if(*uagent == '.') {
return(strdup(s));
}
if(*uagent == '@') {
if(csp->send_user_cookie) {
return(strdup(s));
} else {
if(DEBUG(HDR)) fprintf(logfp, " default");
return(strdup(DEFAULT_USER_AGENT));
}
}
if(DEBUG(HDR)) fprintf(logfp, " modified");
s = strsav(NULL, "User-Agent: ");
s = strsav(s, uagent );
return(s);
}
char *client_ua(struct parsers *v, char *s, struct client_state *csp)
{
if(uagent == NULL) {
if(DEBUG(HDR)) fprintf(logfp, " crunch!");
return(NULL);
}
if(*uagent == '.') {
return(strdup(s));
}
if(*uagent == '@') {
if(csp->send_user_cookie) {
return(strdup(s));
} else {
if(DEBUG(HDR)) fprintf(logfp, " crunch!");
return(NULL);
}
}
if(DEBUG(HDR)) fprintf(logfp, " crunch!");
return(NULL);
}
char *client_from(struct parsers *v, char *s, struct client_state *csp)
{
/* if not set, zap it */
if(from == NULL) {
if(DEBUG(HDR)) fprintf(logfp, " crunch!");
return(NULL);
}
if(*from == '.') {
return(strdup(s));
}
if(DEBUG(HDR)) fprintf(logfp, " modified");
s = strsav(NULL, "From: ");
s = strsav(s, from );
return(s);
}
char *client_send_cookie(struct parsers *v, char *s, struct client_state *csp)
{
if(csp->send_user_cookie) {
enlist(csp->cookie_list, s + v->len + 1);
} else {
if(DEBUG(HDR)) fprintf(logfp, " crunch!");
}
/* always return NULL here. the cookie header will be sent
* at the end of the header.
*/
return(NULL);
}
char *client_x_forwarded(struct parsers *v, char *s, struct client_state *csp)
{
if(add_forwarded) {
csp->x_forwarded = strdup(s);
}
/* always return NULL, since this information
* will be sent at the end of the header.
*/
return(NULL);
}
/* the following functions add headers directly to the header list */
void client_cookie_adder(struct client_state *csp)
{
struct list *l;
char *tmp = NULL;
char *e;
for(l = csp->cookie_list->next; l ; l = l->next) {
if(tmp) {
tmp = strsav(tmp, "; ");
}
tmp = strsav(tmp, l->str);
}
for(l = wafer_list->next; l ; l = l->next) {
if(tmp) {
tmp = strsav(tmp, "; ");
}
if((e = url_encode(cookie_code_map, l->str))) {
tmp = strsav(tmp, e);
freez(e);
}
}
if(tmp) {
char *ret;
ret = strdup("Cookie: ");
ret = strsav(ret, tmp);
if(DEBUG(HDR)) fprintf(logfp, "addh: %s\r\n", ret);
enlist(csp->headers, ret);
freez(tmp);
freez(ret);
}
}
void client_xtra_adder(struct client_state *csp)
{
struct list *l;
for(l = xtra_list->next; l ; l = l->next) {
if(DEBUG(HDR)) fprintf(logfp, "addh: %s\r\n", l->str);
enlist(csp->headers, l->str);
}
}
void client_x_forwarded_adder(struct client_state *csp)
{
char *p = NULL;
if(add_forwarded == 0) return;
if(csp->x_forwarded) {
p = strsav(p, csp->x_forwarded);
p = strsav(p, ", ");
p = strsav(p, csp->ip_addr_str);
} else {
p = strsav(p, "X-Forwarded-For: ");
p = strsav(p, csp->ip_addr_str);
}
if(DEBUG(HDR)) fprintf(logfp, "addh: %s\r\n", p);
enlist(csp->headers, p);
}
char *server_set_cookie(struct parsers *v, char *s, struct client_state *csp)
{
if(jar) fprintf(jar, "%s\t%s\n", csp->http->host, (s + v->len + 1));
if(csp->accept_server_cookie == 0) return(crumble(v, s, csp));
return(strdup(s));
}
/* case insensitive string comparison */
int strcmpic(char *s1, char *s2)
{
while(*s1 && *s2) {
if(( *s1 != *s2)
&& (tolower(*s1) != tolower(*s2))) {
break;
}
s1++, s2++;
}
return(tolower(*s1) - tolower(*s2));
}
int strncmpic(char *s1, char *s2, size_t n)
{
if(n <= 0) return(0);
while(*s1 && *s2) {
if(( *s1 != *s2)
&& (tolower(*s1) != tolower(*s2))) {
break;
}
if(--n <= 0) break;
s1++, s2++;
}
return(tolower(*s1) - tolower(*s2));
}