Commit 155c9b80 authored by Roger Dingledine's avatar Roger Dingledine
Browse files

onion proxy now speaks socks4a

httpap is obsolete; we support privoxy directly now!

smtpap is obsolete; need to find a good socks4a-enabled smtp proxy/client

I dub thee 0.0.1.


svn:r107
parent 8d1aa27c
......@@ -45,7 +45,7 @@ a type, or "command", which indicates what it's for.
3.1. Role.
3. Robustness features.
4. Robustness features.
4.1. Bandwidth throttling. Each cell-speaking connection has a maximum
bandwidth it can use, as specified in the routers.or file. Bandwidth
......
Dependencies:
You're going to need openssl (0.9.5 or later) and popt (1.6 or later).
If you're on Linux, everything will probably work fine. OS X and BSD
(but see below under troubleshooting) now work too. Let us know if
you get it working elsewhere.
You're going to need Privoxy (www.privoxy.org) installed, and configured
to point at a socks4a proxy -- see below.
For tor itself, you're going to need openssl (0.9.5 or later) and popt
(1.6 or later). If you're on Linux, everything will probably work
fine. OS X and BSD (but see below under troubleshooting) now work
too. Let us know if you get it working elsewhere.
If you got the source from cvs:
......@@ -31,11 +34,9 @@ If this doesn't work for you / troubleshooting:
Once you've got it compiled:
It's a bit hard to figure out what to do with the binaries. If you
want to run a local onion proxy (that is, you're a user, not a node
operator), go into src/config and look at the oprc file. You can run an
onion proxy by "../or/or -f oprc". In another window, run something like
"../httpap/httpap -f httpaprc2 -p 9051". See below for how to use it.
If you want to run a local onion proxy (that is, you're a user, not a
node operator), go into src/config and look at the oprc file. You can
run an onion proxy by "../or/or -f oprc". See below for how to use it.
If you want to set up your own test network (that is, act like you're
a full set of node operators), go into src/config/ and look at the
......@@ -48,24 +49,24 @@ Once you've got it compiled:
network. I recommend using a screen session (man screen), or some
other way to handle many windows at once. I open a window for each
onion router, go into the src/config directory, and run something like
"../or/or -f moria2-orrc". In yet another window, I run something like
"../httpap/httpap -f httpaprc -p 9051".
"../or/or -f moria2-orrc".
How to use it:
From here, you can point your browser/etc at localhost:9051 and treat
it as a web proxy. As a first test, you might telnet to it and enter
"GET http://seul.org/ HTTP/1.0" (without the quotes), followed by a pair
of carriage returns (one to separate your request from the headers,
and another to indicate that you're providing no headers). For more
convenient command-line use, I recommend making a ~/.wgetrc with
the line
http_proxy=localhost:9051
Download privoxy (www.privoxy.org). Install it. Add the following
line to your 'config' file:
forward-socks4a / localhost:9050 .
Don't forget the . at the end.
From here, you can point your browser/etc at localhost:8118 and your
traffic will go through Privoxy, then through the onion proxy, to the
onion routing network.
For more convenient command-line use, I recommend making a ~/.wgetrc
with the line
http_proxy=localhost:8118
Then you can do things like "wget seul.org" and watch as it downloads
from the onion routing network.
(You can set your Mozilla/etc to use localhost:9051 as a proxy, and it
will work -- but it will work even better if you tell your Mozilla to
speak only HTTP 1.0 (the http proxy we include doesn't do 1.1 yet.))
For fun, you can wget a very large file (a megabyte or more), and
then ^z the wget a little bit in. The onion routers will continue
......
AC_INIT
AM_INIT_AUTOMAKE(tor, 0.0.0)
AM_INIT_AUTOMAKE(tor, 0.0.1)
AM_CONFIG_HEADER(orconfig.h)
CFLAGS="-Wall -O2"
......@@ -143,5 +143,5 @@ dnl The warning message here is no longer strictly accurate.
AC_CHECK_HEADERS(unistd.h string.h signal.h netdb.h ctype.h poll.h sys/poll.h sys/types.h sys/fcntl.h sys/ioctl.h sys/socket.h sys/time.h netinet/in.h arpa/inet.h errno.h assert.h stdint.h, , AC_MSG_WARN(some headers were not found, compilation may fail))
AC_OUTPUT(Makefile src/Makefile src/common/Makefile src/smtpap/Makefile src/orkeygen/Makefile src/httpap/Makefile src/or/Makefile)
AC_OUTPUT(Makefile src/Makefile src/common/Makefile src/orkeygen/Makefile src/or/Makefile)
# leave in dependency order, since common must be built first
SUBDIRS = common smtpap orkeygen httpap or
DIST_SUBDIRS = common smtpap orkeygen httpap or
SUBDIRS = common orkeygen or
DIST_SUBDIRS = common orkeygen or
EXTRA_DIST = config
......@@ -117,8 +117,6 @@ void connection_free(connection_t *conn) {
free(conn->address);
if(conn->dest_addr)
free(conn->dest_addr);
if(conn->dest_port)
free(conn->dest_port);
if(connection_speaks_cells(conn)) {
if (conn->f_crypto)
......
......@@ -5,6 +5,7 @@
#include "or.h"
extern int global_role; /* from main.c */
static const char socks_userid[] = "anonymous";
int connection_ap_process_inbuf(connection_t *conn) {
......@@ -19,8 +20,8 @@ int connection_ap_process_inbuf(connection_t *conn) {
// log(LOG_DEBUG,"connection_ap_process_inbuf(): state %d.",conn->state);
switch(conn->state) {
case AP_CONN_STATE_SS_WAIT:
return ap_handshake_process_ss(conn);
case AP_CONN_STATE_SOCKS_WAIT:
return ap_handshake_process_socks(conn);
case AP_CONN_STATE_OPEN:
return connection_package_raw_inbuf(conn);
default:
......@@ -30,107 +31,91 @@ int connection_ap_process_inbuf(connection_t *conn) {
return 0;
}
int ap_handshake_process_ss(connection_t *conn) {
uint16_t len;
int ap_handshake_process_socks(connection_t *conn) {
char c;
socks4_t socks4_info;
static char destaddr[512]; /* XXX there's a race condition waiting to happen here */
static int destlen=0;
assert(conn);
log(LOG_DEBUG,"ap_handshake_process_ss() entered.");
log(LOG_DEBUG,"ap_handshake_process_socks() entered.");
if(!conn->ss_received) { /* try to pull it in */
if(!conn->socks_version) { /* try to pull it in */
if(conn->inbuf_datalen < sizeof(ss_t)) /* entire ss available? */
if(conn->inbuf_datalen < sizeof(socks4_t)) /* basic info available? */
return 0; /* not yet */
if(connection_fetch_from_buf((char *)&conn->ss,sizeof(ss_t),conn) < 0)
if(connection_fetch_from_buf((char *)&socks4_info,sizeof(socks4_t),conn) < 0)
return -1;
conn->ss_received = sizeof(ss_t);
log(LOG_DEBUG,"ap_handshake_process_ss(): Successfully read ss.");
log(LOG_DEBUG,"ap_handshake_process_socks(): Successfully read socks info.");
if ((conn->ss.version == 0) || (conn->ss.version != OR_VERSION)) { /* unsupported version */
log(LOG_NOTICE,"ap_handshake_process_ss(): ss: Unsupported version '%c'.",conn->ss.version);
if(tolower(conn->ss.version) == 'g') {
log(LOG_NOTICE,"ap_handshake_process_ss(): are you using the onion proxy as a web proxy?");
}
return -1;
}
if (conn->ss.addr_fmt != SS_ADDR_FMT_ASCII_HOST_PORT) { /* unrecognized address format */
log(LOG_DEBUG,"ap_handshake_process_ss(): ss: Unrecognized address format.");
if(socks4_info.version != 4) {
log(LOG_NOTICE,"ap_handshake_process_socks(): Unrecognized version %d.",socks4_info.version);
ap_handshake_socks_reply(conn, SOCKS4_REQUEST_REJECT);
return -1;
}
}
if(!conn->dest_addr) { /* no dest_addr found yet */
conn->socks_version = socks4_info.version;
if(conn->inbuf_datalen < sizeof(uint16_t))
return 0; /* not yet */
if(connection_fetch_from_buf((char *)&len,sizeof(uint16_t),conn) < 0)
return -1;
len = ntohs(len);
if(len > 512) {
log(LOG_DEBUG,"ap_handshake_process_ss(): Addr length %d too high.",len);
if(socks4_info.command != 1) { /* not a connect? we don't support it. */
log(LOG_NOTICE,"ap_handshake_process_socks(): command %d not '1'.",socks4_info.command);
ap_handshake_socks_reply(conn, SOCKS4_REQUEST_REJECT);
return -1;
}
conn->dest_addr = malloc(len+1);
if(!conn->dest_addr) {
log(LOG_DEBUG,"ap_handshake_process_ss(): Addr malloc failed");
conn->dest_port = ntohs(*(uint16_t*)&socks4_info.destport);
if(!conn->dest_port) {
log(LOG_NOTICE,"ap_handshake_process_socks(): Port is zero.");
ap_handshake_socks_reply(conn, SOCKS4_REQUEST_REJECT);
return -1;
}
conn->dest_addr[len] = 0; /* null terminate it */
conn->dest_addr_len = len;
log(LOG_DEBUG,"Preparing a dest_addr of %d+1 bytes.",len);
}
if(conn->dest_addr_len != conn->dest_addr_received) { /* try to fetch it all in */
if(conn->inbuf_datalen < conn->dest_addr_len)
return 0; /* not yet */
if(connection_fetch_from_buf(conn->dest_addr,conn->dest_addr_len,conn) < 0)
log(LOG_NOTICE,"ap_handshake_process_socks(): Dest port is %d.",conn->dest_port);
if(socks4_info.destip[0] ||
socks4_info.destip[1] ||
socks4_info.destip[2] ||
!socks4_info.destip[3]) { /* must be in form 0.0.0.x, at least for now */
log(LOG_NOTICE,"ap_handshake_process_socks(): destip not in form 0.0.0.x.");
ap_handshake_socks_reply(conn, SOCKS4_REQUEST_REJECT);
return -1;
log(LOG_DEBUG,"ap_handshake_process_ss(): Read dest_addr '%s'.",conn->dest_addr);
}
log(LOG_DEBUG,"ap_handshake_process_socks(): Successfully read destip (0.0.0.x.)");
conn->dest_addr_received = conn->dest_addr_len;
}
/* now do the same thing for port */
if(!conn->dest_port) { /* no dest_port found yet */
if(conn->inbuf_datalen < sizeof(uint16_t))
return 0; /* not yet */
if(connection_fetch_from_buf((char *)&len,sizeof(uint16_t),conn) < 0)
return -1;
len = ntohs(len);
if(len > 10) {
log(LOG_DEBUG,"ap_handshake_process_ss(): Port length %d too high.",len);
return -1;
}
conn->dest_port = malloc(len+1);
if(!conn->dest_port) {
log(LOG_DEBUG,"ap_handshake_process_ss(): Port malloc failed");
return -1;
if(!conn->read_username) { /* the socks spec says we've got to read stuff until we get a null */
while(conn->inbuf_datalen) {
if(connection_fetch_from_buf((char *)&c,1,conn) < 0)
return -1;
if(!c) {
conn->read_username = 1;
log(LOG_DEBUG,"ap_handshake_process_socks(): Successfully read username.");
break;
}
}
conn->dest_port[len] = 0; /* null terminate it */
conn->dest_port_len = len;
log(LOG_DEBUG,"Preparing a dest_port of %d+1 bytes.",len);
}
if(conn->dest_port_len != conn->dest_port_received) { /* try to fetch it all in */
if(conn->inbuf_datalen < conn->dest_port_len)
return 0; /* not yet */
if(connection_fetch_from_buf(conn->dest_port,conn->dest_port_len,conn) < 0)
return -1;
log(LOG_DEBUG,"ap_handshake_process_ss(): Read dest_port '%s'.",conn->dest_port);
if(!conn->dest_addr) { /* no dest_addr found yet */
conn->dest_port_received = conn->dest_port_len;
while(conn->inbuf_datalen) {
if(connection_fetch_from_buf((char *)&c,1,conn) < 0)
return -1;
destaddr[destlen++] = c;
if(destlen > 500) {
log(LOG_NOTICE,"ap_handshake_process_socks(): dest_addr too long!");
ap_handshake_socks_reply(conn, SOCKS4_REQUEST_REJECT);
destlen = 0;
return -1;
}
if(!c) { /* we found the null; we're done */
conn->dest_addr = strdup(destaddr);
destlen = 0;
log(LOG_NOTICE,"ap_handshake_process_socks(): successfully read dest addr '%s'",
conn->dest_addr);
break;
}
}
}
/* now we're all ready to make an onion, etc */
......@@ -291,6 +276,7 @@ int ap_handshake_send_onion(connection_t *ap_conn, connection_t *n_conn, circuit
}
free(tmpbuf);
#if 0
/* deliver the ss in a data cell */
cell.command = CELL_DATA;
cell.aci = circ->n_aci;
......@@ -302,12 +288,13 @@ int ap_handshake_send_onion(connection_t *ap_conn, connection_t *n_conn, circuit
circuit_close(circ);
return -1;
}
#endif
/* deliver the dest_addr in a data cell */
cell.command = CELL_DATA;
cell.aci = circ->n_aci;
cell.length = ap_conn->dest_addr_len+1;
strncpy(cell.payload, ap_conn->dest_addr, ap_conn->dest_addr_len+1);
strncpy(cell.payload, ap_conn->dest_addr, CELL_PAYLOAD_SIZE);
cell.length = strlen(cell.payload)+1;
log(LOG_DEBUG,"ap_handshake_send_onion(): Sending a data cell for addr...");
if(circuit_deliver_data_cell(&cell, circ, circ->n_conn, 'e') < 0) {
log(LOG_DEBUG,"ap_handshake_send_onion(): failed to deliver addr cell. Closing.");
......@@ -318,8 +305,8 @@ int ap_handshake_send_onion(connection_t *ap_conn, connection_t *n_conn, circuit
/* deliver the dest_port in a data cell */
cell.command = CELL_DATA;
cell.aci = circ->n_aci;
cell.length = ap_conn->dest_port_len+1;
strncpy(cell.payload, ap_conn->dest_port, ap_conn->dest_port_len+1);
snprintf(cell.payload, CELL_PAYLOAD_SIZE, "%d", ap_conn->dest_port);
cell.length = strlen(cell.payload)+1;
log(LOG_DEBUG,"ap_handshake_send_onion(): Sending a data cell for port...");
if(circuit_deliver_data_cell(&cell, circ, circ->n_conn, 'e') < 0) {
log(LOG_DEBUG,"ap_handshake_send_onion(): failed to deliver port cell. Closing.");
......@@ -336,13 +323,24 @@ int ap_handshake_send_onion(connection_t *ap_conn, connection_t *n_conn, circuit
return 0;
}
int connection_ap_send_connected(connection_t *conn) {
char zero=0;
int ap_handshake_socks_reply(connection_t *conn, char result) {
socks4_t socks4_info;
assert(conn);
/* give the AP a "0" byte, because it wants to hear that we've connected */
return connection_write_to_buf(&zero, 1, conn);
socks4_info.version = 4;
socks4_info.command = result;
socks4_info.destport[0] = socks4_info.destport[1] = 0;
socks4_info.destip[0] = socks4_info.destip[1] = socks4_info.destip[2] = socks4_info.destip[3] = 0;
connection_write_to_buf((char *)&socks4_info, sizeof(socks4_t), conn);
return connection_flush_buf(conn); /* try to flush it, in case we're about to close the conn */
}
int connection_ap_send_connected(connection_t *conn) {
assert(conn);
return ap_handshake_socks_reply(conn, SOCKS4_REQUEST_GRANTED);
}
int connection_ap_process_data_cell(cell_t *cell, connection_t *conn) {
......@@ -388,7 +386,7 @@ int connection_ap_create_listener(crypto_pk_env_t *prkey, struct sockaddr_in *lo
}
int connection_ap_handle_listener_read(connection_t *conn) {
log(LOG_NOTICE,"AP: Received a connection request. Waiting for SS.");
return connection_handle_listener_read(conn, CONN_TYPE_AP, AP_CONN_STATE_SS_WAIT);
log(LOG_NOTICE,"AP: Received a connection request. Waiting for socksinfo.");
return connection_handle_listener_read(conn, CONN_TYPE_AP, AP_CONN_STATE_SOCKS_WAIT);
}
......@@ -93,6 +93,7 @@ int connection_exit_process_data_cell(cell_t *cell, connection_t *conn) {
switch(conn->state) {
case EXIT_CONN_STATE_CONNECTING_WAIT:
log(LOG_DEBUG,"connection_exit_process_data_cell(): state is connecting_wait. cell length %d.", cell->length);
#if 0
if(!conn->ss_received) { /* this cell contains the ss */
if(cell->length != sizeof(ss_t)) {
log(LOG_DEBUG,"connection_exit_process_data_cell(): Supposed to contain SS but wrong size. Closing.");
......@@ -104,8 +105,10 @@ int connection_exit_process_data_cell(cell_t *cell, connection_t *conn) {
return -1;
}
conn->ss_received = 1;
log(LOG_DEBUG,"connection_exit_process_data_cell(): SS received.");
} else if (!conn->addr) { /* this cell contains the dest addr */
log(LOG_DEBUG,"connection_exit_process_data_cell(): SS received.");
} else
#endif
if (!conn->addr) { /* this cell contains the dest addr */
if(!memchr(cell->payload,0,cell->length)) {
log(LOG_DEBUG,"connection_exit_process_data_cell(): dest_addr cell has no \\0. Closing.");
return -1;
......@@ -117,7 +120,7 @@ int connection_exit_process_data_cell(cell_t *cell, connection_t *conn) {
return -1;
}
memcpy(&conn->addr, rent->h_addr,rent->h_length);
log(LOG_DEBUG,"connection_exit_process_data_cell(): addr is %s.",cell->payload);
log(LOG_DEBUG,"connection_exit_process_data_cell(): addr is %s.",cell->payload);
} else if (!conn->port) { /* this cell contains the dest port */
if(!memchr(cell->payload,'\0',cell->length)) {
log(LOG_DEBUG,"connection_exit_process_data_cell(): dest_port cell has no \\0. Closing.");
......@@ -167,6 +170,10 @@ int connection_exit_process_data_cell(cell_t *cell, connection_t *conn) {
conn->s = s;
connection_set_poll_socket(conn);
conn->state = EXIT_CONN_STATE_OPEN;
if(connection_wants_to_flush(conn)) { /* in case there are any queued data cells */
log(LOG_NOTICE,"connection_exit_process_data_cell(): tell roger: newly connected conn had data waiting!");
// connection_start_writing(conn);
}
connection_watch_events(conn, POLLIN);
/* also, deliver a 'connected' cell back through the circuit. */
......
......@@ -13,8 +13,6 @@ static connection_t *connection_array[MAXCONNECTIONS] =
{ NULL };
static struct pollfd poll_array[MAXCONNECTIONS];
/* = { [0 ... MAXCONNECTIONS-1] = { -1, 0, 0 } };
*/
static int nfds=0; /* number of connections currently active */
......
......@@ -46,7 +46,7 @@
can be overridden by config file */
#define MAX_BUF_SIZE (640*1024)
#define DEFAULT_BANDWIDTH_OP 1024
#define DEFAULT_BANDWIDTH_OP 102400
#define ACI_TYPE_LOWER 0
#define ACI_TYPE_HIGHER 1
......@@ -100,7 +100,7 @@
#define EXIT_CONN_STATE_CLOSE_WAIT 4 /* have sent a destroy, awaiting a confirmation */
#endif
#define AP_CONN_STATE_SS_WAIT 0
#define AP_CONN_STATE_SOCKS_WAIT 0
#define AP_CONN_STATE_OR_WAIT 1
#define AP_CONN_STATE_OPEN 2
......@@ -147,6 +147,21 @@ typedef struct
unsigned char payload[120];
} cell_t;
#define SOCKS4_REQUEST_GRANTED 90
#define SOCKS4_REQUEST_REJECT 91
#define SOCKS4_REQUEST_IDENT_FAILED 92
#define SOCKS4_REQUEST_IDENT_CONFLICT 93
/* structure of a socks client operation */
typedef struct {
unsigned char version; /* socks version number */
unsigned char command; /* command code */
unsigned char destport[2]; /* destination port, network order */
unsigned char destip[4]; /* destination address */
/* userid follows, terminated by a NULL */
/* dest host follows, terminated by a NULL */
} socks4_t;
typedef struct
{
......@@ -190,12 +205,14 @@ typedef struct
/* used by exit and ap: */
ss_t ss; /* standard structure */
int ss_received; /* size of ss, received so far */
// ss_t ss; /* standard structure */
// int ss_received; /* size of ss, received so far */
char socks_version;
char read_username;
char *dest_addr, *dest_port;
uint16_t dest_addr_len, dest_port_len;
uint16_t dest_addr_received, dest_port_received;
char *dest_addr;
uint16_t dest_port;
/* used by OR, to keep state while connect()ing: Kludge. */
......@@ -460,7 +477,7 @@ int connection_finished_flushing(connection_t *conn);
int connection_ap_process_inbuf(connection_t *conn);
int ap_handshake_process_ss(connection_t *conn);
int ap_handshake_process_socks(connection_t *conn);
int ap_handshake_create_onion(connection_t *conn);
......@@ -472,6 +489,7 @@ int ap_handshake_n_conn_open(connection_t *or_conn);
int ap_handshake_send_onion(connection_t *ap_conn, connection_t *or_conn, circuit_t *circ);
int ap_handshake_socks_reply(connection_t *conn, char result);
int connection_ap_send_connected(connection_t *conn);
int connection_ap_process_data_cell(cell_t *cell, connection_t *conn);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment