2006-02-09 06:46:49 +01:00
|
|
|
/* Copyright (c) 2001 Matej Pfajfar.
|
|
|
|
* Copyright (c) 2001-2004, Roger Dingledine.
|
2007-12-12 22:09:01 +01:00
|
|
|
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
2010-02-27 23:13:37 +01:00
|
|
|
* Copyright (c) 2007-2010, The Tor Project, Inc. */
|
Implemented link padding and receiver token buckets
Each socket reads at most 'bandwidth' bytes per second sustained, but
can handle bursts of up to 10*bandwidth bytes.
Cells are now sent out at evenly-spaced intervals, with padding sent
out otherwise. Set Linkpadding=0 in the rc file to send cells as soon
as they're available (and to never send padding cells).
Added license/copyrights statements at the top of most files.
router->min and router->max have been merged into a single 'bandwidth'
value. We should make the routerinfo_t reflect this (want to do that,
Mat?)
As the bandwidth increases, and we want to stop sleeping more and more
frequently to send a single cell, cpu usage goes up. At 128kB/s we're
pretty much calling poll with a timeout of 1ms or even 0ms. The current
code takes a timeout of 0-9ms and makes it 10ms. prepare_for_poll()
handles everything that should have happened in the past, so as long as
our buffers don't get too full in that 10ms, we're ok.
Speaking of too full, if you run three servers at 100kB/s with -l debug,
it spends too much time printing debugging messages to be able to keep
up with the cells. The outbuf ultimately fills up and it kills that
connection. If you run with -l err, it works fine up through 500kB/s and
probably beyond. Down the road we'll want to teach it to recognize when
an outbuf is getting full, and back off.
svn:r50
2002-07-16 03:12:15 +02:00
|
|
|
/* See LICENSE for licensing information */
|
2002-06-27 00:45:49 +02:00
|
|
|
|
2004-05-07 19:04:12 +02:00
|
|
|
/**
|
|
|
|
* \file buffers.c
|
2008-09-09 22:43:31 +02:00
|
|
|
* \brief Implements a generic interface buffer. Buffers are
|
2005-06-11 07:31:17 +02:00
|
|
|
* fairly opaque string holders that can read to or flush from:
|
|
|
|
* memory, file descriptors, or TLS connections.
|
2004-05-07 19:04:12 +02:00
|
|
|
**/
|
2008-02-21 00:20:36 +01:00
|
|
|
#define BUFFERS_PRIVATE
|
2002-06-27 00:45:49 +02:00
|
|
|
#include "or.h"
|
2010-07-22 00:46:18 +02:00
|
|
|
#include "buffers.h"
|
2010-07-22 10:22:51 +02:00
|
|
|
#include "config.h"
|
2010-07-22 10:43:02 +02:00
|
|
|
#include "connection_edge.h"
|
2010-07-22 10:50:34 +02:00
|
|
|
#include "connection_or.h"
|
2010-07-22 11:35:09 +02:00
|
|
|
#include "control.h"
|
2010-07-23 21:08:30 +02:00
|
|
|
#include "reasons.h"
|
2009-09-29 06:44:39 +02:00
|
|
|
#include "../common/util.h"
|
2010-07-10 03:52:20 +02:00
|
|
|
#include "../common/torlog.h"
|
2008-06-11 19:56:52 +02:00
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
2007-12-26 19:09:36 +01:00
|
|
|
//#define PARANOIA
|
2005-04-26 22:53:22 +02:00
|
|
|
|
2005-04-27 02:53:44 +02:00
|
|
|
#ifdef PARANOIA
|
2008-02-12 21:20:52 +01:00
|
|
|
/** Helper: If PARANOIA is defined, assert that the buffer in local variable
|
|
|
|
* <b>buf</b> is well-formed. */
|
2007-06-17 20:22:39 +02:00
|
|
|
#define check() STMT_BEGIN assert_buf_ok(buf); STMT_END
|
2005-04-27 02:53:44 +02:00
|
|
|
#else
|
2007-06-17 20:22:39 +02:00
|
|
|
#define check() STMT_NIL
|
2005-04-27 02:53:44 +02:00
|
|
|
#endif
|
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
/* Implementation notes:
|
|
|
|
*
|
|
|
|
* After flirting with memmove, and dallying with ring-buffers, we're finally
|
|
|
|
* getting up to speed with the 1970s and implementing buffers as a linked
|
|
|
|
* list of small chunks. Each buffer has such a list; data is removed from
|
|
|
|
* the head of the list, and added at the tail. The list is singly linked,
|
|
|
|
* and the buffer keeps a pointer to the head and the tail.
|
|
|
|
*
|
|
|
|
* Every chunk, except the tail, contains at least one byte of data. Data in
|
|
|
|
* each chunk is contiguous.
|
|
|
|
*
|
|
|
|
* When you need to treat the first N characters on a buffer as a contiguous
|
|
|
|
* string, use the buf_pullup function to make them so. Don't do this more
|
|
|
|
* than necessary.
|
|
|
|
*
|
|
|
|
* The major free Unix kernels have handled buffers like this since, like,
|
|
|
|
* forever.
|
2005-06-08 19:27:11 +02:00
|
|
|
*/
|
2005-04-26 22:53:22 +02:00
|
|
|
|
2009-07-31 23:03:35 +02:00
|
|
|
static int parse_socks(const char *data, size_t datalen, socks_request_t *req,
|
|
|
|
int log_sockstype, int safe_socks, ssize_t *drain_out,
|
|
|
|
size_t *want_length_out);
|
2009-08-26 17:55:36 +02:00
|
|
|
static int parse_socks_client(const uint8_t *data, size_t datalen,
|
|
|
|
int state, char **reason,
|
|
|
|
ssize_t *drain_out);
|
2009-07-31 23:03:35 +02:00
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
/* Chunk manipulation functions */
|
|
|
|
|
|
|
|
/** A single chunk on a buffer or in a freelist. */
|
|
|
|
typedef struct chunk_t {
|
|
|
|
struct chunk_t *next; /**< The next chunk on the buffer or freelist. */
|
|
|
|
size_t datalen; /**< The number of bytes stored in this chunk */
|
|
|
|
size_t memlen; /**< The number of usable bytes of storage in <b>mem</b>. */
|
|
|
|
char *data; /**< A pointer to the first byte of data stored in <b>mem</b>. */
|
|
|
|
char mem[1]; /**< The actual memory used for storage in this chunk. May be
|
|
|
|
* more than one byte long. */
|
|
|
|
} chunk_t;
|
|
|
|
|
2008-07-31 14:18:14 +02:00
|
|
|
#define CHUNK_HEADER_LEN STRUCT_OFFSET(chunk_t, mem[0])
|
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
/** Return the number of bytes needed to allocate a chunk to hold
|
|
|
|
* <b>memlen</b> bytes. */
|
2008-07-31 14:18:14 +02:00
|
|
|
#define CHUNK_ALLOC_SIZE(memlen) (CHUNK_HEADER_LEN + (memlen))
|
2007-12-26 01:12:08 +01:00
|
|
|
/** Return the number of usable bytes in a chunk allocated with
|
|
|
|
* malloc(<b>memlen</b>). */
|
2008-07-31 14:18:14 +02:00
|
|
|
#define CHUNK_SIZE_WITH_ALLOC(memlen) ((memlen) - CHUNK_HEADER_LEN)
|
2007-12-26 01:12:08 +01:00
|
|
|
|
|
|
|
/** Return the next character in <b>chunk</b> onto which data can be appended.
|
|
|
|
* If the chunk is full, this might be off the end of chunk->mem. */
|
2005-06-11 20:52:12 +02:00
|
|
|
static INLINE char *
|
2007-12-26 01:12:08 +01:00
|
|
|
CHUNK_WRITE_PTR(chunk_t *chunk)
|
2005-04-26 22:53:22 +02:00
|
|
|
{
|
2007-12-26 01:12:08 +01:00
|
|
|
return chunk->data + chunk->datalen;
|
2005-04-26 22:53:22 +02:00
|
|
|
}
|
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
/** Return the number of bytes that can be written onto <b>chunk</b> without
|
|
|
|
* running out of space. */
|
|
|
|
static INLINE size_t
|
|
|
|
CHUNK_REMAINING_CAPACITY(const chunk_t *chunk)
|
2005-06-17 20:49:55 +02:00
|
|
|
{
|
2007-12-26 01:12:08 +01:00
|
|
|
return (chunk->mem + chunk->memlen) - (chunk->data + chunk->datalen);
|
2005-04-26 22:53:22 +02:00
|
|
|
}
|
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
/** Move all bytes stored in <b>chunk</b> to the front of <b>chunk</b>->mem,
|
|
|
|
* to free up space at the end. */
|
|
|
|
static INLINE void
|
|
|
|
chunk_repack(chunk_t *chunk)
|
2005-06-17 20:49:55 +02:00
|
|
|
{
|
2007-12-26 01:12:08 +01:00
|
|
|
if (chunk->datalen && chunk->data != &chunk->mem[0]) {
|
|
|
|
memmove(chunk->mem, chunk->data, chunk->datalen);
|
|
|
|
}
|
|
|
|
chunk->data = &chunk->mem[0];
|
2005-06-17 20:49:55 +02:00
|
|
|
}
|
|
|
|
|
2008-01-13 01:20:44 +01:00
|
|
|
#ifdef ENABLE_BUF_FREELISTS
|
2007-12-26 01:12:08 +01:00
|
|
|
/** A freelist of chunks. */
|
|
|
|
typedef struct chunk_freelist_t {
|
|
|
|
size_t alloc_size; /**< What size chunks does this freelist hold? */
|
|
|
|
int max_length; /**< Never allow more than this number of chunks in the
|
|
|
|
* freelist. */
|
|
|
|
int slack; /**< When trimming the freelist, leave this number of extra
|
|
|
|
* chunks beyond lowest_length.*/
|
|
|
|
int cur_length; /**< How many chunks on the freelist now? */
|
|
|
|
int lowest_length; /**< What's the smallest value of cur_length since the
|
|
|
|
* last time we cleaned this freelist? */
|
2007-12-27 15:20:30 +01:00
|
|
|
uint64_t n_alloc;
|
|
|
|
uint64_t n_free;
|
|
|
|
uint64_t n_hit;
|
2007-12-26 01:12:08 +01:00
|
|
|
chunk_t *head; /**< First chunk on the freelist. */
|
|
|
|
} chunk_freelist_t;
|
|
|
|
|
|
|
|
/** Macro to help define freelists. */
|
2007-12-27 15:20:30 +01:00
|
|
|
#define FL(a,m,s) { a, m, s, 0, 0, 0, 0, 0, NULL }
|
2007-12-26 01:12:08 +01:00
|
|
|
|
|
|
|
/** Static array of freelists, sorted by alloc_len, terminated by an entry
|
|
|
|
* with alloc_size of 0. */
|
|
|
|
static chunk_freelist_t freelists[] = {
|
2008-02-16 00:39:04 +01:00
|
|
|
FL(4096, 256, 8), FL(8192, 128, 4), FL(16384, 64, 4), FL(32768, 32, 2),
|
2007-12-29 06:16:30 +01:00
|
|
|
FL(0, 0, 0)
|
2007-12-26 01:12:08 +01:00
|
|
|
};
|
|
|
|
#undef FL
|
2008-02-12 21:20:52 +01:00
|
|
|
/** How many times have we looked for a chunk of a size that no freelist
|
|
|
|
* could help with? */
|
2007-12-27 15:20:30 +01:00
|
|
|
static uint64_t n_freelist_miss = 0;
|
2007-12-26 01:12:08 +01:00
|
|
|
|
|
|
|
static void assert_freelist_ok(chunk_freelist_t *fl);
|
|
|
|
|
|
|
|
/** Return the freelist to hold chunks of size <b>alloc</b>, or NULL if
|
|
|
|
* no freelist exists for that size. */
|
|
|
|
static INLINE chunk_freelist_t *
|
|
|
|
get_freelist(size_t alloc)
|
2005-04-26 22:53:22 +02:00
|
|
|
{
|
2007-12-26 01:12:08 +01:00
|
|
|
int i;
|
|
|
|
for (i=0; freelists[i].alloc_size <= alloc; ++i) {
|
|
|
|
if (freelists[i].alloc_size == alloc) {
|
|
|
|
return &freelists[i];
|
|
|
|
}
|
2005-04-26 22:53:22 +02:00
|
|
|
}
|
2007-12-26 01:12:08 +01:00
|
|
|
return NULL;
|
2005-04-26 22:53:22 +02:00
|
|
|
}
|
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
/** Deallocate a chunk or put it on a freelist */
|
|
|
|
static void
|
2009-09-28 16:37:01 +02:00
|
|
|
chunk_free_unchecked(chunk_t *chunk)
|
2007-05-10 00:39:49 +02:00
|
|
|
{
|
2009-09-28 16:37:01 +02:00
|
|
|
size_t alloc;
|
|
|
|
chunk_freelist_t *freelist;
|
|
|
|
|
|
|
|
alloc = CHUNK_ALLOC_SIZE(chunk->memlen);
|
|
|
|
freelist = get_freelist(alloc);
|
2007-12-26 01:12:08 +01:00
|
|
|
if (freelist && freelist->cur_length < freelist->max_length) {
|
|
|
|
chunk->next = freelist->head;
|
|
|
|
freelist->head = chunk;
|
|
|
|
++freelist->cur_length;
|
2007-05-10 00:39:49 +02:00
|
|
|
} else {
|
2007-12-27 15:20:30 +01:00
|
|
|
if (freelist)
|
|
|
|
++freelist->n_free;
|
2007-12-26 01:12:08 +01:00
|
|
|
tor_free(chunk);
|
2007-05-10 00:39:49 +02:00
|
|
|
}
|
|
|
|
}
|
2007-04-23 16:42:27 +02:00
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
/** Allocate a new chunk with a given allocation size, or get one from the
|
2009-05-27 23:55:51 +02:00
|
|
|
* freelist. Note that a chunk with allocation size A can actually hold only
|
2007-12-26 01:12:08 +01:00
|
|
|
* CHUNK_SIZE_WITH_ALLOC(A) bytes in its mem field. */
|
|
|
|
static INLINE chunk_t *
|
|
|
|
chunk_new_with_alloc_size(size_t alloc)
|
2007-07-27 20:33:37 +02:00
|
|
|
{
|
2007-12-26 01:12:08 +01:00
|
|
|
chunk_t *ch;
|
|
|
|
chunk_freelist_t *freelist;
|
|
|
|
tor_assert(alloc >= sizeof(chunk_t));
|
|
|
|
freelist = get_freelist(alloc);
|
|
|
|
if (freelist && freelist->head) {
|
|
|
|
ch = freelist->head;
|
|
|
|
freelist->head = ch->next;
|
|
|
|
if (--freelist->cur_length < freelist->lowest_length)
|
|
|
|
freelist->lowest_length = freelist->cur_length;
|
2007-12-27 15:20:30 +01:00
|
|
|
++freelist->n_hit;
|
2007-12-26 01:12:08 +01:00
|
|
|
} else {
|
2008-12-18 17:11:24 +01:00
|
|
|
/* XXXX take advantage of tor_malloc_roundup, once we know how that
|
2008-02-06 06:31:21 +01:00
|
|
|
* affects freelists. */
|
2007-12-27 15:20:30 +01:00
|
|
|
if (freelist)
|
|
|
|
++freelist->n_alloc;
|
|
|
|
else
|
|
|
|
++n_freelist_miss;
|
2007-12-26 01:12:08 +01:00
|
|
|
ch = tor_malloc(alloc);
|
2007-07-27 20:33:37 +02:00
|
|
|
}
|
2007-12-26 01:12:08 +01:00
|
|
|
ch->next = NULL;
|
|
|
|
ch->datalen = 0;
|
|
|
|
ch->memlen = CHUNK_SIZE_WITH_ALLOC(alloc);
|
|
|
|
ch->data = &ch->mem[0];
|
|
|
|
return ch;
|
2007-07-27 20:33:37 +02:00
|
|
|
}
|
2008-01-13 01:20:44 +01:00
|
|
|
#else
|
|
|
|
static void
|
2009-09-28 16:37:01 +02:00
|
|
|
chunk_free_unchecked(chunk_t *chunk)
|
2008-01-13 01:20:44 +01:00
|
|
|
{
|
|
|
|
tor_free(chunk);
|
|
|
|
}
|
|
|
|
static INLINE chunk_t *
|
|
|
|
chunk_new_with_alloc_size(size_t alloc)
|
|
|
|
{
|
|
|
|
chunk_t *ch;
|
|
|
|
ch = tor_malloc_roundup(&alloc);
|
|
|
|
ch->next = NULL;
|
|
|
|
ch->datalen = 0;
|
|
|
|
ch->memlen = CHUNK_SIZE_WITH_ALLOC(alloc);
|
|
|
|
ch->data = &ch->mem[0];
|
|
|
|
return ch;
|
|
|
|
}
|
|
|
|
#endif
|
2007-07-27 20:33:37 +02:00
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
/** Expand <b>chunk</b> until it can hold <b>sz</b> bytes, and return a
|
|
|
|
* new pointer to <b>chunk</b>. Old pointers are no longer valid. */
|
|
|
|
static INLINE chunk_t *
|
|
|
|
chunk_grow(chunk_t *chunk, size_t sz)
|
|
|
|
{
|
|
|
|
off_t offset;
|
|
|
|
tor_assert(sz > chunk->memlen);
|
|
|
|
offset = chunk->data - chunk->mem;
|
|
|
|
chunk = tor_realloc(chunk, CHUNK_ALLOC_SIZE(sz));
|
|
|
|
chunk->memlen = sz;
|
|
|
|
chunk->data = chunk->mem + offset;
|
|
|
|
return chunk;
|
2007-04-23 16:42:27 +02:00
|
|
|
}
|
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
/** If a read onto the end of a chunk would be smaller than this number, then
|
|
|
|
* just start a new chunk. */
|
|
|
|
#define MIN_READ_LEN 8
|
|
|
|
/** Every chunk should take up at least this many bytes. */
|
|
|
|
#define MIN_CHUNK_ALLOC 256
|
2008-02-12 21:20:52 +01:00
|
|
|
/** No chunk should take up more than this many bytes. */
|
2007-12-26 01:12:08 +01:00
|
|
|
#define MAX_CHUNK_ALLOC 65536
|
|
|
|
|
|
|
|
/** Return the allocation size we'd like to use to hold <b>target</b>
|
|
|
|
* bytes. */
|
|
|
|
static INLINE size_t
|
|
|
|
preferred_chunk_size(size_t target)
|
2007-04-23 16:42:27 +02:00
|
|
|
{
|
2007-12-26 01:12:08 +01:00
|
|
|
size_t sz = MIN_CHUNK_ALLOC;
|
|
|
|
while (CHUNK_SIZE_WITH_ALLOC(sz) < target) {
|
|
|
|
sz <<= 1;
|
2007-04-23 16:42:27 +02:00
|
|
|
}
|
2007-12-26 01:12:08 +01:00
|
|
|
return sz;
|
2007-04-23 16:42:27 +02:00
|
|
|
}
|
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
/** Remove from the freelists most chunks that have not been used since the
|
|
|
|
* last call to buf_shrink_freelists(). */
|
2007-05-09 23:43:41 +02:00
|
|
|
void
|
2007-07-17 11:26:45 +02:00
|
|
|
buf_shrink_freelists(int free_all)
|
2007-05-09 23:43:41 +02:00
|
|
|
{
|
2008-01-13 01:20:44 +01:00
|
|
|
#ifdef ENABLE_BUF_FREELISTS
|
2007-12-26 01:12:08 +01:00
|
|
|
int i;
|
2010-11-12 09:46:26 +01:00
|
|
|
disable_control_logging();
|
2007-12-26 01:12:08 +01:00
|
|
|
for (i = 0; freelists[i].alloc_size; ++i) {
|
|
|
|
int slack = freelists[i].slack;
|
|
|
|
assert_freelist_ok(&freelists[i]);
|
|
|
|
if (free_all || freelists[i].lowest_length > slack) {
|
|
|
|
int n_to_free = free_all ? freelists[i].cur_length :
|
|
|
|
(freelists[i].lowest_length - slack);
|
|
|
|
int n_to_skip = freelists[i].cur_length - n_to_free;
|
2010-11-12 09:21:03 +01:00
|
|
|
int orig_length = freelists[i].cur_length;
|
2009-05-12 19:54:21 +02:00
|
|
|
int orig_n_to_free = n_to_free, n_freed=0;
|
2010-08-10 21:58:41 +02:00
|
|
|
int orig_n_to_skip = n_to_skip;
|
2007-12-27 04:27:48 +01:00
|
|
|
int new_length = n_to_skip;
|
2007-12-26 01:12:08 +01:00
|
|
|
chunk_t **chp = &freelists[i].head;
|
|
|
|
chunk_t *chunk;
|
|
|
|
while (n_to_skip) {
|
2010-08-10 21:58:41 +02:00
|
|
|
if (! (*chp)->next) {
|
|
|
|
log_warn(LD_BUG, "I wanted to skip %d chunks in the freelist for "
|
|
|
|
"%d-byte chunks, but only found %d. (Length %d)",
|
|
|
|
orig_n_to_skip, (int)freelists[i].alloc_size,
|
|
|
|
orig_n_to_skip-n_to_skip, freelists[i].cur_length);
|
|
|
|
assert_freelist_ok(&freelists[i]);
|
2010-11-12 19:05:58 +01:00
|
|
|
goto done;
|
2010-08-10 21:58:41 +02:00
|
|
|
}
|
|
|
|
// tor_assert((*chp)->next);
|
2007-12-26 01:12:08 +01:00
|
|
|
chp = &(*chp)->next;
|
2007-12-27 04:23:57 +01:00
|
|
|
--n_to_skip;
|
2007-07-17 13:33:38 +02:00
|
|
|
}
|
2007-12-26 01:12:08 +01:00
|
|
|
chunk = *chp;
|
|
|
|
*chp = NULL;
|
|
|
|
while (chunk) {
|
|
|
|
chunk_t *next = chunk->next;
|
|
|
|
tor_free(chunk);
|
|
|
|
chunk = next;
|
|
|
|
--n_to_free;
|
2009-05-12 19:54:21 +02:00
|
|
|
++n_freed;
|
2007-12-27 15:20:30 +01:00
|
|
|
++freelists[i].n_free;
|
2007-05-24 20:12:41 +02:00
|
|
|
}
|
2009-05-12 19:54:21 +02:00
|
|
|
if (n_to_free) {
|
|
|
|
log_warn(LD_BUG, "Freelist length for %d-byte chunks may have been "
|
|
|
|
"messed up somehow.", (int)freelists[i].alloc_size);
|
|
|
|
log_warn(LD_BUG, "There were %d chunks at the start. I decided to "
|
|
|
|
"keep %d. I wanted to free %d. I freed %d. I somehow think "
|
|
|
|
"I have %d left to free.",
|
|
|
|
freelists[i].cur_length, n_to_skip, orig_n_to_free,
|
|
|
|
n_freed, n_to_free);
|
|
|
|
}
|
|
|
|
// tor_assert(!n_to_free);
|
2007-12-27 04:27:48 +01:00
|
|
|
freelists[i].cur_length = new_length;
|
2010-11-12 09:21:03 +01:00
|
|
|
log_info(LD_MM, "Cleaned freelist for %d-byte chunks: original "
|
|
|
|
"length %d, kept %d, dropped %d.",
|
|
|
|
(int)freelists[i].alloc_size, orig_length,
|
|
|
|
orig_n_to_skip, orig_n_to_free);
|
2007-05-09 23:43:41 +02:00
|
|
|
}
|
2007-12-27 01:25:54 +01:00
|
|
|
freelists[i].lowest_length = freelists[i].cur_length;
|
2007-12-26 01:12:08 +01:00
|
|
|
assert_freelist_ok(&freelists[i]);
|
2007-05-09 23:43:41 +02:00
|
|
|
}
|
2010-11-12 19:05:58 +01:00
|
|
|
done:
|
2010-11-12 09:46:26 +01:00
|
|
|
enable_control_logging();
|
2008-01-13 01:20:44 +01:00
|
|
|
#else
|
|
|
|
(void) free_all;
|
|
|
|
#endif
|
2007-05-09 23:43:41 +02:00
|
|
|
}
|
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
/** Describe the current status of the freelists at log level <b>severity</b>.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
buf_dump_freelist_sizes(int severity)
|
2003-10-14 03:34:31 +02:00
|
|
|
{
|
2008-01-13 01:20:44 +01:00
|
|
|
#ifdef ENABLE_BUF_FREELISTS
|
2007-12-26 01:12:08 +01:00
|
|
|
int i;
|
|
|
|
log(severity, LD_MM, "====== Buffer freelists:");
|
|
|
|
for (i = 0; freelists[i].alloc_size; ++i) {
|
|
|
|
uint64_t total = ((uint64_t)freelists[i].cur_length) *
|
|
|
|
freelists[i].alloc_size;
|
|
|
|
log(severity, LD_MM,
|
2007-12-27 15:20:30 +01:00
|
|
|
U64_FORMAT" bytes in %d %d-byte chunks ["U64_FORMAT
|
|
|
|
" misses; "U64_FORMAT" frees; "U64_FORMAT" hits]",
|
|
|
|
U64_PRINTF_ARG(total),
|
|
|
|
freelists[i].cur_length, (int)freelists[i].alloc_size,
|
|
|
|
U64_PRINTF_ARG(freelists[i].n_alloc),
|
|
|
|
U64_PRINTF_ARG(freelists[i].n_free),
|
|
|
|
U64_PRINTF_ARG(freelists[i].n_hit));
|
2007-12-26 01:12:08 +01:00
|
|
|
}
|
2007-12-27 15:20:30 +01:00
|
|
|
log(severity, LD_MM, U64_FORMAT" allocations in non-freelist sizes",
|
|
|
|
U64_PRINTF_ARG(n_freelist_miss));
|
2008-01-13 01:20:44 +01:00
|
|
|
#else
|
|
|
|
(void)severity;
|
|
|
|
#endif
|
2007-12-26 01:12:08 +01:00
|
|
|
}
|
2005-04-26 22:53:22 +02:00
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
/** Magic value for buf_t.magic, to catch pointer errors. */
|
|
|
|
#define BUFFER_MAGIC 0xB0FFF312u
|
|
|
|
/** A resizeable buffer, optimized for reading and writing. */
|
|
|
|
struct buf_t {
|
|
|
|
uint32_t magic; /**< Magic cookie for debugging: Must be set to
|
|
|
|
* BUFFER_MAGIC. */
|
|
|
|
size_t datalen; /**< How many bytes is this buffer holding right now? */
|
|
|
|
size_t default_chunk_size; /**< Don't allocate any chunks smaller than
|
|
|
|
* this for this buffer. */
|
|
|
|
chunk_t *head; /**< First chunk in the list, or NULL for none. */
|
|
|
|
chunk_t *tail; /**< Last chunk in the list, or NULL for none. */
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Collapse data from the first N chunks from <b>buf</b> into buf->head,
|
|
|
|
* growing it as necessary, until buf->head has the first <b>bytes</b> bytes
|
|
|
|
* of data from the buffer, or until buf->head has all the data in <b>buf</b>.
|
|
|
|
*
|
|
|
|
* If <b>nulterminate</b> is true, ensure that there is a 0 byte in
|
|
|
|
* buf->head->mem right after all the data. */
|
|
|
|
static void
|
|
|
|
buf_pullup(buf_t *buf, size_t bytes, int nulterminate)
|
|
|
|
{
|
|
|
|
chunk_t *dest, *src;
|
|
|
|
size_t capacity;
|
|
|
|
if (!buf->head)
|
2005-05-03 01:17:08 +02:00
|
|
|
return;
|
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
check();
|
|
|
|
if (buf->datalen < bytes)
|
|
|
|
bytes = buf->datalen;
|
|
|
|
|
|
|
|
if (nulterminate) {
|
|
|
|
capacity = bytes + 1;
|
|
|
|
if (buf->head->datalen >= bytes && CHUNK_REMAINING_CAPACITY(buf->head)) {
|
|
|
|
*CHUNK_WRITE_PTR(buf->head) = '\0';
|
|
|
|
return;
|
2005-04-26 22:53:22 +02:00
|
|
|
}
|
2007-12-26 01:12:08 +01:00
|
|
|
} else {
|
|
|
|
capacity = bytes;
|
|
|
|
if (buf->head->datalen >= bytes)
|
|
|
|
return;
|
2005-04-26 22:53:22 +02:00
|
|
|
}
|
2005-06-08 19:27:11 +02:00
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
if (buf->head->memlen >= capacity) {
|
|
|
|
/* We don't need to grow the first chunk, but we might need to repack it.*/
|
|
|
|
if (CHUNK_REMAINING_CAPACITY(buf->head) < capacity-buf->datalen)
|
|
|
|
chunk_repack(buf->head);
|
|
|
|
tor_assert(CHUNK_REMAINING_CAPACITY(buf->head) >= capacity-buf->datalen);
|
2005-06-08 19:27:11 +02:00
|
|
|
} else {
|
2007-12-26 01:12:08 +01:00
|
|
|
chunk_t *newhead;
|
|
|
|
size_t newsize;
|
|
|
|
/* We need to grow the chunk. */
|
|
|
|
chunk_repack(buf->head);
|
|
|
|
newsize = CHUNK_SIZE_WITH_ALLOC(preferred_chunk_size(capacity));
|
|
|
|
newhead = chunk_grow(buf->head, newsize);
|
|
|
|
tor_assert(newhead->memlen >= capacity);
|
|
|
|
if (newhead != buf->head) {
|
|
|
|
if (buf->tail == buf->head)
|
|
|
|
buf->tail = newhead;
|
|
|
|
buf->head = newhead;
|
2007-04-23 16:42:27 +02:00
|
|
|
}
|
2005-06-08 19:27:11 +02:00
|
|
|
}
|
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
dest = buf->head;
|
|
|
|
while (dest->datalen < bytes) {
|
|
|
|
size_t n = bytes - dest->datalen;
|
|
|
|
src = dest->next;
|
|
|
|
tor_assert(src);
|
|
|
|
if (n > src->datalen) {
|
|
|
|
memcpy(CHUNK_WRITE_PTR(dest), src->data, src->datalen);
|
|
|
|
dest->datalen += src->datalen;
|
|
|
|
dest->next = src->next;
|
|
|
|
if (buf->tail == src)
|
|
|
|
buf->tail = dest;
|
2009-09-28 16:37:01 +02:00
|
|
|
chunk_free_unchecked(src);
|
2007-12-26 01:12:08 +01:00
|
|
|
} else {
|
|
|
|
memcpy(CHUNK_WRITE_PTR(dest), src->data, n);
|
|
|
|
dest->datalen += n;
|
|
|
|
src->data += n;
|
|
|
|
src->datalen -= n;
|
|
|
|
tor_assert(dest->datalen == bytes);
|
|
|
|
}
|
2005-04-26 22:53:22 +02:00
|
|
|
}
|
2007-12-26 01:12:08 +01:00
|
|
|
|
|
|
|
if (nulterminate) {
|
|
|
|
tor_assert(CHUNK_REMAINING_CAPACITY(buf->head));
|
|
|
|
*CHUNK_WRITE_PTR(buf->head) = '\0';
|
2005-04-26 22:53:22 +02:00
|
|
|
}
|
2003-10-14 03:34:31 +02:00
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
check();
|
2003-10-14 03:34:31 +02:00
|
|
|
}
|
|
|
|
|
2005-05-03 01:41:39 +02:00
|
|
|
/** Resize buf so it won't hold extra memory that we haven't been
|
2008-02-16 00:39:04 +01:00
|
|
|
* using lately.
|
2005-05-03 01:39:09 +02:00
|
|
|
*/
|
2005-05-03 00:49:24 +02:00
|
|
|
void
|
|
|
|
buf_shrink(buf_t *buf)
|
|
|
|
{
|
2007-12-26 01:12:08 +01:00
|
|
|
(void)buf;
|
2005-05-03 00:49:24 +02:00
|
|
|
}
|
|
|
|
|
2005-06-11 23:17:38 +02:00
|
|
|
/** Remove the first <b>n</b> bytes from buf. */
|
2005-06-11 20:52:12 +02:00
|
|
|
static INLINE void
|
2005-09-30 03:09:52 +02:00
|
|
|
buf_remove_from_front(buf_t *buf, size_t n)
|
|
|
|
{
|
2004-04-25 22:37:37 +02:00
|
|
|
tor_assert(buf->datalen >= n);
|
2007-12-26 01:12:08 +01:00
|
|
|
while (n) {
|
|
|
|
tor_assert(buf->head);
|
|
|
|
if (buf->head->datalen > n) {
|
|
|
|
buf->head->datalen -= n;
|
|
|
|
buf->head->data += n;
|
|
|
|
buf->datalen -= n;
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
chunk_t *victim = buf->head;
|
|
|
|
n -= victim->datalen;
|
|
|
|
buf->datalen -= victim->datalen;
|
|
|
|
buf->head = victim->next;
|
|
|
|
if (buf->tail == victim)
|
|
|
|
buf->tail = NULL;
|
2009-09-28 16:37:01 +02:00
|
|
|
chunk_free_unchecked(victim);
|
2007-07-30 19:47:43 +02:00
|
|
|
}
|
2005-05-03 01:32:23 +02:00
|
|
|
}
|
2005-04-27 02:53:44 +02:00
|
|
|
check();
|
2003-10-14 03:34:31 +02:00
|
|
|
}
|
|
|
|
|
2008-02-16 00:39:04 +01:00
|
|
|
/** Create and return a new buf with default chunk capacity <b>size</b>.
|
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
buf_t *
|
2005-09-30 03:09:52 +02:00
|
|
|
buf_new_with_capacity(size_t size)
|
|
|
|
{
|
2007-12-26 01:12:08 +01:00
|
|
|
buf_t *b = buf_new();
|
|
|
|
b->default_chunk_size = preferred_chunk_size(size);
|
|
|
|
return b;
|
2003-09-25 07:17:11 +02:00
|
|
|
}
|
2002-06-27 00:45:49 +02:00
|
|
|
|
2004-05-07 19:04:12 +02:00
|
|
|
/** Allocate and return a new buffer with default capacity. */
|
2005-06-11 20:52:12 +02:00
|
|
|
buf_t *
|
|
|
|
buf_new(void)
|
2003-09-25 07:17:11 +02:00
|
|
|
{
|
2007-12-26 01:12:08 +01:00
|
|
|
buf_t *buf = tor_malloc_zero(sizeof(buf_t));
|
|
|
|
buf->magic = BUFFER_MAGIC;
|
|
|
|
buf->default_chunk_size = 4096;
|
|
|
|
return buf;
|
2003-09-25 07:17:11 +02:00
|
|
|
}
|
2002-06-27 00:45:49 +02:00
|
|
|
|
2005-06-11 23:17:38 +02:00
|
|
|
/** Remove all data from <b>buf</b>. */
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
|
|
|
buf_clear(buf_t *buf)
|
2004-02-28 20:14:11 +01:00
|
|
|
{
|
2007-12-26 01:12:08 +01:00
|
|
|
chunk_t *chunk, *next;
|
2004-02-28 20:14:11 +01:00
|
|
|
buf->datalen = 0;
|
2007-12-26 01:12:08 +01:00
|
|
|
for (chunk = buf->head; chunk; chunk = next) {
|
|
|
|
next = chunk->next;
|
2009-09-28 16:37:01 +02:00
|
|
|
chunk_free_unchecked(chunk);
|
2007-12-26 01:12:08 +01:00
|
|
|
}
|
|
|
|
buf->head = buf->tail = NULL;
|
2004-02-28 20:14:11 +01:00
|
|
|
}
|
2002-06-27 00:45:49 +02:00
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/** Return the number of bytes stored in <b>buf</b> */
|
2005-06-11 20:52:12 +02:00
|
|
|
size_t
|
|
|
|
buf_datalen(const buf_t *buf)
|
2003-09-25 07:17:11 +02:00
|
|
|
{
|
|
|
|
return buf->datalen;
|
2002-06-27 00:45:49 +02:00
|
|
|
}
|
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
/** Return the total length of all chunks used in <b>buf</b>. */
|
2005-06-11 20:52:12 +02:00
|
|
|
size_t
|
2007-12-26 01:12:08 +01:00
|
|
|
buf_allocation(const buf_t *buf)
|
2003-09-25 07:17:11 +02:00
|
|
|
{
|
2007-12-26 01:12:08 +01:00
|
|
|
size_t total = 0;
|
|
|
|
const chunk_t *chunk;
|
|
|
|
for (chunk = buf->head; chunk; chunk = chunk->next) {
|
|
|
|
total += chunk->memlen;
|
|
|
|
}
|
|
|
|
return total;
|
2003-09-25 07:17:11 +02:00
|
|
|
}
|
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
/** Return the number of bytes that can be added to <b>buf</b> without
|
|
|
|
* performing any additional allocation. */
|
|
|
|
size_t
|
|
|
|
buf_slack(const buf_t *buf)
|
2003-09-25 07:17:11 +02:00
|
|
|
{
|
2007-12-26 01:12:08 +01:00
|
|
|
if (!buf->tail)
|
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return CHUNK_REMAINING_CAPACITY(buf->tail);
|
2003-09-25 07:17:11 +02:00
|
|
|
}
|
|
|
|
|
2005-06-11 23:17:38 +02:00
|
|
|
/** Release storage held by <b>buf</b>. */
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
|
|
|
buf_free(buf_t *buf)
|
|
|
|
{
|
2009-09-28 16:37:01 +02:00
|
|
|
if (!buf)
|
|
|
|
return;
|
2009-07-31 17:11:45 +02:00
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
buf_clear(buf);
|
|
|
|
buf->magic = 0xdeadbeef;
|
|
|
|
tor_free(buf);
|
|
|
|
}
|
|
|
|
|
2008-01-06 01:54:22 +01:00
|
|
|
/** Append a new chunk with enough capacity to hold <b>capacity</b> bytes to
|
|
|
|
* the tail of <b>buf</b>. If <b>capped</b>, don't allocate a chunk bigger
|
|
|
|
* than MAX_CHUNK_ALLOC. */
|
2007-12-26 01:12:08 +01:00
|
|
|
static chunk_t *
|
2007-12-29 06:16:30 +01:00
|
|
|
buf_add_chunk_with_capacity(buf_t *buf, size_t capacity, int capped)
|
2007-12-26 01:12:08 +01:00
|
|
|
{
|
|
|
|
chunk_t *chunk;
|
2007-12-29 06:16:30 +01:00
|
|
|
if (CHUNK_ALLOC_SIZE(capacity) < buf->default_chunk_size) {
|
2007-12-26 01:12:08 +01:00
|
|
|
chunk = chunk_new_with_alloc_size(buf->default_chunk_size);
|
2007-12-29 06:16:30 +01:00
|
|
|
} else if (capped && CHUNK_ALLOC_SIZE(capacity) > MAX_CHUNK_ALLOC) {
|
|
|
|
chunk = chunk_new_with_alloc_size(MAX_CHUNK_ALLOC);
|
2007-12-26 01:12:08 +01:00
|
|
|
} else {
|
2007-12-29 06:16:30 +01:00
|
|
|
chunk = chunk_new_with_alloc_size(preferred_chunk_size(capacity));
|
2007-05-10 00:39:49 +02:00
|
|
|
}
|
2007-12-26 01:12:08 +01:00
|
|
|
if (buf->tail) {
|
|
|
|
tor_assert(buf->head);
|
|
|
|
buf->tail->next = chunk;
|
|
|
|
buf->tail = chunk;
|
|
|
|
} else {
|
|
|
|
tor_assert(!buf->head);
|
|
|
|
buf->head = buf->tail = chunk;
|
2007-04-23 16:42:27 +02:00
|
|
|
}
|
2007-12-26 01:12:08 +01:00
|
|
|
check();
|
|
|
|
return chunk;
|
2002-06-27 00:45:49 +02:00
|
|
|
}
|
|
|
|
|
2008-02-06 20:34:32 +01:00
|
|
|
/** Read up to <b>at_most</b> bytes from the socket <b>fd</b> into
|
2008-02-12 21:20:52 +01:00
|
|
|
* <b>chunk</b> (which must be on <b>buf</b>). If we get an EOF, set
|
2008-02-06 20:34:32 +01:00
|
|
|
* *<b>reached_eof</b> to 1. Return -1 on error, 0 on eof or blocking,
|
|
|
|
* and the number of bytes read otherwise. */
|
2005-06-11 20:52:12 +02:00
|
|
|
static INLINE int
|
2007-12-26 01:12:08 +01:00
|
|
|
read_to_chunk(buf_t *buf, chunk_t *chunk, int fd, size_t at_most,
|
2008-09-14 10:35:41 +02:00
|
|
|
int *reached_eof, int *socket_error)
|
2005-04-26 22:53:22 +02:00
|
|
|
{
|
2008-02-22 04:44:36 +01:00
|
|
|
ssize_t read_result;
|
2008-06-11 19:56:52 +02:00
|
|
|
if (at_most > CHUNK_REMAINING_CAPACITY(chunk))
|
|
|
|
at_most = CHUNK_REMAINING_CAPACITY(chunk);
|
2007-12-26 01:12:08 +01:00
|
|
|
read_result = tor_socket_recv(fd, CHUNK_WRITE_PTR(chunk), at_most, 0);
|
2008-06-11 19:56:52 +02:00
|
|
|
|
2005-04-26 22:53:22 +02:00
|
|
|
if (read_result < 0) {
|
2007-12-27 06:18:36 +01:00
|
|
|
int e = tor_socket_errno(fd);
|
2005-04-26 22:53:22 +02:00
|
|
|
if (!ERRNO_IS_EAGAIN(e)) { /* it's a real error */
|
2006-04-08 09:54:11 +02:00
|
|
|
#ifdef MS_WINDOWS
|
|
|
|
if (e == WSAENOBUFS)
|
|
|
|
log_warn(LD_NET,"recv() failed: WSAENOBUFS. Not enough ram?");
|
|
|
|
#endif
|
2008-09-14 10:35:41 +02:00
|
|
|
*socket_error = e;
|
2005-04-26 22:53:22 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0; /* would block. */
|
|
|
|
} else if (read_result == 0) {
|
2007-12-26 01:12:08 +01:00
|
|
|
log_debug(LD_NET,"Encountered eof on fd %d", (int)fd);
|
2005-04-26 22:53:22 +02:00
|
|
|
*reached_eof = 1;
|
|
|
|
return 0;
|
2007-12-26 01:12:08 +01:00
|
|
|
} else { /* actually got bytes. */
|
2005-04-26 22:53:22 +02:00
|
|
|
buf->datalen += read_result;
|
2007-12-26 01:12:08 +01:00
|
|
|
chunk->datalen += read_result;
|
2008-02-22 04:44:36 +01:00
|
|
|
log_debug(LD_NET,"Read %ld bytes. %d on inbuf.", (long)read_result,
|
2006-02-13 09:28:42 +01:00
|
|
|
(int)buf->datalen);
|
2008-02-22 04:44:36 +01:00
|
|
|
tor_assert(read_result < INT_MAX);
|
|
|
|
return (int)read_result;
|
2005-04-26 22:53:22 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-06 20:34:32 +01:00
|
|
|
/** As read_to_chunk(), but return (negative) error code on error, blocking,
|
|
|
|
* or TLS, and the number of bytes read otherwise. */
|
2007-12-26 01:12:08 +01:00
|
|
|
static INLINE int
|
|
|
|
read_to_chunk_tls(buf_t *buf, chunk_t *chunk, tor_tls_t *tls,
|
|
|
|
size_t at_most)
|
|
|
|
{
|
|
|
|
int read_result;
|
|
|
|
|
|
|
|
tor_assert(CHUNK_REMAINING_CAPACITY(chunk) >= at_most);
|
|
|
|
read_result = tor_tls_read(tls, CHUNK_WRITE_PTR(chunk), at_most);
|
|
|
|
if (read_result < 0)
|
|
|
|
return read_result;
|
|
|
|
buf->datalen += read_result;
|
|
|
|
chunk->datalen += read_result;
|
|
|
|
return read_result;
|
|
|
|
}
|
|
|
|
|
2004-05-10 09:27:29 +02:00
|
|
|
/** Read from socket <b>s</b>, writing onto end of <b>buf</b>. Read at most
|
2008-02-06 20:34:32 +01:00
|
|
|
* <b>at_most</b> bytes, growing the buffer as necessary. If recv() returns 0
|
|
|
|
* (because of EOF), set *<b>reached_eof</b> to 1 and return 0. Return -1 on
|
|
|
|
* error; else return the number of bytes read.
|
2003-03-04 05:36:37 +01:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
2008-09-14 10:35:41 +02:00
|
|
|
read_to_buf(int s, size_t at_most, buf_t *buf, int *reached_eof,
|
|
|
|
int *socket_error)
|
2005-04-26 22:53:22 +02:00
|
|
|
{
|
2007-12-26 01:12:08 +01:00
|
|
|
int r = 0;
|
|
|
|
size_t total_read = 0;
|
2002-06-27 00:45:49 +02:00
|
|
|
|
2005-04-27 02:53:44 +02:00
|
|
|
check();
|
2007-12-26 01:12:08 +01:00
|
|
|
tor_assert(reached_eof);
|
|
|
|
tor_assert(s >= 0);
|
|
|
|
|
2007-12-29 06:16:30 +01:00
|
|
|
while (at_most > total_read) {
|
|
|
|
size_t readlen = at_most - total_read;
|
2007-12-26 01:12:08 +01:00
|
|
|
chunk_t *chunk;
|
|
|
|
if (!buf->tail || CHUNK_REMAINING_CAPACITY(buf->tail) < MIN_READ_LEN) {
|
2007-12-29 06:16:30 +01:00
|
|
|
chunk = buf_add_chunk_with_capacity(buf, at_most, 1);
|
|
|
|
if (readlen > chunk->memlen)
|
|
|
|
readlen = chunk->memlen;
|
2005-04-26 22:53:22 +02:00
|
|
|
} else {
|
2007-12-26 01:12:08 +01:00
|
|
|
size_t cap = CHUNK_REMAINING_CAPACITY(buf->tail);
|
|
|
|
chunk = buf->tail;
|
|
|
|
if (cap < readlen)
|
|
|
|
readlen = cap;
|
2002-06-27 00:45:49 +02:00
|
|
|
}
|
2005-04-26 22:53:22 +02:00
|
|
|
|
2008-09-14 10:35:41 +02:00
|
|
|
r = read_to_chunk(buf, chunk, s, readlen, reached_eof, socket_error);
|
2007-12-26 01:12:08 +01:00
|
|
|
check();
|
|
|
|
if (r < 0)
|
|
|
|
return r; /* Error */
|
2008-03-02 23:29:04 +01:00
|
|
|
tor_assert(total_read+r < INT_MAX);
|
2007-12-26 01:12:08 +01:00
|
|
|
total_read += r;
|
2008-03-02 23:29:04 +01:00
|
|
|
if ((size_t)r < readlen) { /* eof, block, or no more to read. */
|
|
|
|
break;
|
|
|
|
}
|
2007-12-26 01:12:08 +01:00
|
|
|
}
|
2008-03-02 23:29:04 +01:00
|
|
|
return (int)total_read;
|
2002-06-27 00:45:49 +02:00
|
|
|
}
|
|
|
|
|
2008-02-06 20:34:32 +01:00
|
|
|
/** As read_to_buf, but reads from a TLS connection, and returns a TLS
|
|
|
|
* status value rather than the number of bytes read.
|
2005-06-11 08:07:22 +02:00
|
|
|
*
|
|
|
|
* Using TLS on OR connections complicates matters in two ways.
|
|
|
|
*
|
|
|
|
* First, a TLS stream has its own read buffer independent of the
|
|
|
|
* connection's read buffer. (TLS needs to read an entire frame from
|
|
|
|
* the network before it can decrypt any data. Thus, trying to read 1
|
|
|
|
* byte from TLS can require that several KB be read from the network
|
|
|
|
* and decrypted. The extra data is stored in TLS's decrypt buffer.)
|
|
|
|
* Because the data hasn't been read by Tor (it's still inside the TLS),
|
|
|
|
* this means that sometimes a connection "has stuff to read" even when
|
|
|
|
* poll() didn't return POLLIN. The tor_tls_get_pending_bytes function is
|
|
|
|
* used in connection.c to detect TLS objects with non-empty internal
|
|
|
|
* buffers and read from them again.
|
|
|
|
*
|
|
|
|
* Second, the TLS stream's events do not correspond directly to network
|
|
|
|
* events: sometimes, before a TLS stream can read, the network must be
|
|
|
|
* ready to write -- or vice versa.
|
2004-05-02 00:08:43 +02:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
2005-10-06 06:33:40 +02:00
|
|
|
read_to_buf_tls(tor_tls_t *tls, size_t at_most, buf_t *buf)
|
2005-06-11 20:52:12 +02:00
|
|
|
{
|
2007-12-26 01:12:08 +01:00
|
|
|
int r = 0;
|
|
|
|
size_t total_read = 0;
|
2005-04-27 02:53:44 +02:00
|
|
|
check();
|
2005-04-26 22:53:22 +02:00
|
|
|
|
2007-12-29 06:16:30 +01:00
|
|
|
while (at_most > total_read) {
|
|
|
|
size_t readlen = at_most - total_read;
|
2007-12-26 01:12:08 +01:00
|
|
|
chunk_t *chunk;
|
|
|
|
if (!buf->tail || CHUNK_REMAINING_CAPACITY(buf->tail) < MIN_READ_LEN) {
|
2007-12-29 06:16:30 +01:00
|
|
|
chunk = buf_add_chunk_with_capacity(buf, at_most, 1);
|
|
|
|
if (readlen > chunk->memlen)
|
|
|
|
readlen = chunk->memlen;
|
2007-12-26 01:12:08 +01:00
|
|
|
} else {
|
|
|
|
size_t cap = CHUNK_REMAINING_CAPACITY(buf->tail);
|
|
|
|
chunk = buf->tail;
|
|
|
|
if (cap < readlen)
|
|
|
|
readlen = cap;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = read_to_chunk_tls(buf, chunk, tls, readlen);
|
2005-04-27 02:53:44 +02:00
|
|
|
check();
|
2007-12-26 01:12:08 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r; /* Error */
|
2008-03-02 23:29:04 +01:00
|
|
|
tor_assert(total_read+r < INT_MAX);
|
|
|
|
total_read += r;
|
|
|
|
if ((size_t)r < readlen) /* eof, block, or no more to read. */
|
|
|
|
break;
|
2005-04-26 22:53:22 +02:00
|
|
|
}
|
2008-03-02 23:29:04 +01:00
|
|
|
return (int)total_read;
|
2003-12-17 22:09:31 +01:00
|
|
|
}
|
2003-09-04 18:05:08 +02:00
|
|
|
|
2008-02-06 20:34:32 +01:00
|
|
|
/** Helper for flush_buf(): try to write <b>sz</b> bytes from chunk
|
|
|
|
* <b>chunk</b> of buffer <b>buf</b> onto socket <b>s</b>. On success, deduct
|
|
|
|
* the bytes written from *<b>buf_flushlen</b>. Return the number of bytes
|
|
|
|
* written on success, 0 on blocking, -1 on failure.
|
2005-06-11 20:52:12 +02:00
|
|
|
*/
|
2005-04-26 22:53:22 +02:00
|
|
|
static INLINE int
|
2007-12-26 01:12:08 +01:00
|
|
|
flush_chunk(int s, buf_t *buf, chunk_t *chunk, size_t sz,
|
2008-02-06 20:34:32 +01:00
|
|
|
size_t *buf_flushlen)
|
2005-04-26 22:53:22 +02:00
|
|
|
{
|
2008-02-22 04:44:36 +01:00
|
|
|
ssize_t write_result;
|
2009-07-31 20:55:17 +02:00
|
|
|
|
2008-06-11 19:56:52 +02:00
|
|
|
if (sz > chunk->datalen)
|
|
|
|
sz = chunk->datalen;
|
2007-12-26 01:12:08 +01:00
|
|
|
write_result = tor_socket_send(s, chunk->data, sz, 0);
|
2008-06-11 19:56:52 +02:00
|
|
|
|
2005-04-26 22:53:22 +02:00
|
|
|
if (write_result < 0) {
|
|
|
|
int e = tor_socket_errno(s);
|
|
|
|
if (!ERRNO_IS_EAGAIN(e)) { /* it's a real error */
|
2006-04-08 09:54:11 +02:00
|
|
|
#ifdef MS_WINDOWS
|
|
|
|
if (e == WSAENOBUFS)
|
|
|
|
log_warn(LD_NET,"write() failed: WSAENOBUFS. Not enough ram?");
|
|
|
|
#endif
|
2005-04-26 22:53:22 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2006-02-13 09:28:42 +01:00
|
|
|
log_debug(LD_NET,"write() would block, returning.");
|
2005-04-26 22:53:22 +02:00
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
*buf_flushlen -= write_result;
|
|
|
|
buf_remove_from_front(buf, write_result);
|
2008-02-22 04:44:36 +01:00
|
|
|
tor_assert(write_result < INT_MAX);
|
|
|
|
return (int)write_result;
|
2005-04-26 22:53:22 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-08 22:13:15 +01:00
|
|
|
/** Helper for flush_buf_tls(): try to write <b>sz</b> bytes from chunk
|
|
|
|
* <b>chunk</b> of buffer <b>buf</b> onto socket <b>s</b>. (Tries to write
|
|
|
|
* more if there is a forced pending write size.) On success, deduct the
|
|
|
|
* bytes written from *<b>buf_flushlen</b>. Return the number of bytes
|
2009-05-27 23:55:51 +02:00
|
|
|
* written on success, and a TOR_TLS error code on failure or blocking.
|
2008-02-08 22:13:15 +01:00
|
|
|
*/
|
2007-12-26 01:12:08 +01:00
|
|
|
static INLINE int
|
|
|
|
flush_chunk_tls(tor_tls_t *tls, buf_t *buf, chunk_t *chunk,
|
2007-12-26 20:02:15 +01:00
|
|
|
size_t sz, size_t *buf_flushlen)
|
2007-12-26 01:12:08 +01:00
|
|
|
{
|
|
|
|
int r;
|
|
|
|
size_t forced;
|
2007-12-26 20:02:15 +01:00
|
|
|
char *data;
|
2007-12-26 01:12:08 +01:00
|
|
|
|
|
|
|
forced = tor_tls_get_forced_write_size(tls);
|
|
|
|
if (forced > sz)
|
|
|
|
sz = forced;
|
2007-12-26 20:02:15 +01:00
|
|
|
if (chunk) {
|
|
|
|
data = chunk->data;
|
|
|
|
tor_assert(sz <= chunk->datalen);
|
|
|
|
} else {
|
|
|
|
data = NULL;
|
|
|
|
tor_assert(sz == 0);
|
|
|
|
}
|
|
|
|
r = tor_tls_write(tls, data, sz);
|
2007-12-26 01:12:08 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2007-12-26 19:55:56 +01:00
|
|
|
if (*buf_flushlen > (size_t)r)
|
|
|
|
*buf_flushlen -= r;
|
|
|
|
else
|
|
|
|
*buf_flushlen = 0;
|
2007-12-26 01:12:08 +01:00
|
|
|
buf_remove_from_front(buf, r);
|
|
|
|
log_debug(LD_NET,"flushed %d bytes, %d ready to flush, %d remain.",
|
|
|
|
r,(int)*buf_flushlen,(int)buf->datalen);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/** Write data from <b>buf</b> to the socket <b>s</b>. Write at most
|
2005-10-29 20:19:37 +02:00
|
|
|
* <b>sz</b> bytes, decrement *<b>buf_flushlen</b> by
|
2004-05-09 18:47:25 +02:00
|
|
|
* the number of bytes actually written, and remove the written bytes
|
|
|
|
* from the buffer. Return the number of bytes written on success,
|
|
|
|
* -1 on failure. Return 0 if write() would block.
|
2004-05-02 00:08:43 +02:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
2005-10-29 20:19:37 +02:00
|
|
|
flush_buf(int s, buf_t *buf, size_t sz, size_t *buf_flushlen)
|
2003-09-25 07:17:11 +02:00
|
|
|
{
|
2005-04-26 22:53:22 +02:00
|
|
|
int r;
|
|
|
|
size_t flushed = 0;
|
2004-10-17 00:14:52 +02:00
|
|
|
tor_assert(buf_flushlen);
|
2007-12-26 01:12:08 +01:00
|
|
|
tor_assert(s >= 0);
|
2004-10-17 00:14:52 +02:00
|
|
|
tor_assert(*buf_flushlen <= buf->datalen);
|
2005-10-29 20:19:37 +02:00
|
|
|
tor_assert(sz <= *buf_flushlen);
|
2002-06-27 00:45:49 +02:00
|
|
|
|
2005-04-27 02:53:44 +02:00
|
|
|
check();
|
2007-12-26 01:12:08 +01:00
|
|
|
while (sz) {
|
|
|
|
size_t flushlen0;
|
|
|
|
tor_assert(buf->head);
|
|
|
|
if (buf->head->datalen >= sz)
|
|
|
|
flushlen0 = sz;
|
|
|
|
else
|
|
|
|
flushlen0 = buf->head->datalen;
|
2005-04-26 22:53:22 +02:00
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
r = flush_chunk(s, buf, buf->head, flushlen0, buf_flushlen);
|
2005-04-27 02:53:44 +02:00
|
|
|
check();
|
2007-12-26 01:12:08 +01:00
|
|
|
if (r < 0)
|
2005-04-26 22:53:22 +02:00
|
|
|
return r;
|
|
|
|
flushed += r;
|
2007-12-26 01:12:08 +01:00
|
|
|
sz -= r;
|
2007-12-26 23:07:14 +01:00
|
|
|
if (r == 0 || (size_t)r < flushlen0) /* can't flush any more now. */
|
|
|
|
break;
|
2005-04-26 22:53:22 +02:00
|
|
|
}
|
2008-02-22 04:44:36 +01:00
|
|
|
tor_assert(flushed < INT_MAX);
|
|
|
|
return (int)flushed;
|
2005-04-26 22:53:22 +02:00
|
|
|
}
|
2003-10-14 03:34:31 +02:00
|
|
|
|
2008-02-08 22:13:15 +01:00
|
|
|
/** As flush_buf(), but writes data to a TLS connection. Can write more than
|
|
|
|
* <b>flushlen</b> bytes.
|
2004-05-02 00:08:43 +02:00
|
|
|
*/
|
2005-09-30 03:09:52 +02:00
|
|
|
int
|
2008-01-06 01:54:22 +01:00
|
|
|
flush_buf_tls(tor_tls_t *tls, buf_t *buf, size_t flushlen,
|
|
|
|
size_t *buf_flushlen)
|
2003-09-04 18:05:08 +02:00
|
|
|
{
|
|
|
|
int r;
|
2007-12-26 01:12:08 +01:00
|
|
|
size_t flushed = 0;
|
2007-12-26 19:55:56 +01:00
|
|
|
ssize_t sz;
|
2004-10-17 00:14:52 +02:00
|
|
|
tor_assert(buf_flushlen);
|
2005-10-29 20:19:37 +02:00
|
|
|
tor_assert(*buf_flushlen <= buf->datalen);
|
2007-12-26 19:55:56 +01:00
|
|
|
tor_assert(flushlen <= *buf_flushlen);
|
|
|
|
sz = (ssize_t) flushlen;
|
2003-09-07 12:24:40 +02:00
|
|
|
|
|
|
|
/* we want to let tls write even if flushlen is zero, because it might
|
|
|
|
* have a partial record pending */
|
2005-04-23 16:26:02 +02:00
|
|
|
check_no_tls_errors();
|
2005-04-26 22:53:22 +02:00
|
|
|
|
2005-04-27 02:53:44 +02:00
|
|
|
check();
|
2007-12-26 20:02:15 +01:00
|
|
|
do {
|
2007-12-26 01:12:08 +01:00
|
|
|
size_t flushlen0;
|
2007-12-26 01:36:05 +01:00
|
|
|
if (buf->head) {
|
2007-12-26 19:55:56 +01:00
|
|
|
if ((ssize_t)buf->head->datalen >= sz)
|
2007-12-26 01:36:05 +01:00
|
|
|
flushlen0 = sz;
|
|
|
|
else
|
|
|
|
flushlen0 = buf->head->datalen;
|
|
|
|
} else {
|
|
|
|
flushlen0 = 0;
|
|
|
|
}
|
2005-04-26 22:53:22 +02:00
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
r = flush_chunk_tls(tls, buf, buf->head, flushlen0, buf_flushlen);
|
2005-04-27 02:53:44 +02:00
|
|
|
check();
|
2007-12-26 01:12:08 +01:00
|
|
|
if (r < 0)
|
2005-04-26 22:53:22 +02:00
|
|
|
return r;
|
|
|
|
flushed += r;
|
2007-12-26 01:12:08 +01:00
|
|
|
sz -= r;
|
2007-12-26 23:07:14 +01:00
|
|
|
if (r == 0) /* Can't flush any more now. */
|
|
|
|
break;
|
2007-12-26 20:02:15 +01:00
|
|
|
} while (sz > 0);
|
2008-02-22 04:44:36 +01:00
|
|
|
tor_assert(flushed < INT_MAX);
|
|
|
|
return (int)flushed;
|
2003-09-04 18:05:08 +02:00
|
|
|
}
|
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/** Append <b>string_len</b> bytes from <b>string</b> to the end of
|
|
|
|
* <b>buf</b>.
|
|
|
|
*
|
2004-05-02 00:08:43 +02:00
|
|
|
* Return the new length of the buffer on success, -1 on failure.
|
|
|
|
*/
|
2005-04-26 22:53:22 +02:00
|
|
|
int
|
|
|
|
write_to_buf(const char *string, size_t string_len, buf_t *buf)
|
|
|
|
{
|
2007-12-26 01:12:08 +01:00
|
|
|
if (!string_len)
|
2008-02-22 04:44:36 +01:00
|
|
|
return (int)buf->datalen;
|
2007-12-26 01:12:08 +01:00
|
|
|
check();
|
2002-06-27 00:45:49 +02:00
|
|
|
|
2007-12-29 06:16:30 +01:00
|
|
|
while (string_len) {
|
|
|
|
size_t copy;
|
|
|
|
if (!buf->tail || !CHUNK_REMAINING_CAPACITY(buf->tail))
|
|
|
|
buf_add_chunk_with_capacity(buf, string_len, 1);
|
|
|
|
|
|
|
|
copy = CHUNK_REMAINING_CAPACITY(buf->tail);
|
2007-12-26 01:12:08 +01:00
|
|
|
if (copy > string_len)
|
|
|
|
copy = string_len;
|
|
|
|
memcpy(CHUNK_WRITE_PTR(buf->tail), string, copy);
|
|
|
|
string_len -= copy;
|
|
|
|
string += copy;
|
|
|
|
buf->datalen += copy;
|
|
|
|
buf->tail->datalen += copy;
|
2003-12-14 09:15:41 +01:00
|
|
|
}
|
2003-10-14 03:34:31 +02:00
|
|
|
|
2005-04-27 02:53:44 +02:00
|
|
|
check();
|
2008-02-22 04:44:36 +01:00
|
|
|
tor_assert(buf->datalen < INT_MAX);
|
|
|
|
return (int)buf->datalen;
|
2003-03-17 03:42:45 +01:00
|
|
|
}
|
|
|
|
|
2005-06-11 23:17:38 +02:00
|
|
|
/** Helper: copy the first <b>string_len</b> bytes from <b>buf</b>
|
|
|
|
* onto <b>string</b>.
|
2005-06-11 20:52:12 +02:00
|
|
|
*/
|
|
|
|
static INLINE void
|
2007-12-26 01:12:08 +01:00
|
|
|
peek_from_buf(char *string, size_t string_len, const buf_t *buf)
|
2005-04-26 22:53:22 +02:00
|
|
|
{
|
2007-12-26 01:12:08 +01:00
|
|
|
chunk_t *chunk;
|
2002-06-27 00:45:49 +02:00
|
|
|
|
2004-04-25 22:37:37 +02:00
|
|
|
tor_assert(string);
|
2005-12-14 21:40:40 +01:00
|
|
|
/* make sure we don't ask for too much */
|
|
|
|
tor_assert(string_len <= buf->datalen);
|
2005-11-30 23:48:58 +01:00
|
|
|
/* assert_buf_ok(buf); */
|
2002-06-27 00:45:49 +02:00
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
chunk = buf->head;
|
|
|
|
while (string_len) {
|
|
|
|
size_t copy = string_len;
|
|
|
|
tor_assert(chunk);
|
|
|
|
if (chunk->datalen < copy)
|
|
|
|
copy = chunk->datalen;
|
|
|
|
memcpy(string, chunk->data, copy);
|
|
|
|
string_len -= copy;
|
|
|
|
string += copy;
|
|
|
|
chunk = chunk->next;
|
2005-04-26 22:53:22 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-12-14 21:40:40 +01:00
|
|
|
/** Remove <b>string_len</b> bytes from the front of <b>buf</b>, and store
|
|
|
|
* them into <b>string</b>. Return the new buffer size. <b>string_len</b>
|
|
|
|
* must be \<= the number of bytes on the buffer.
|
2005-04-26 22:53:22 +02:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
|
|
|
fetch_from_buf(char *string, size_t string_len, buf_t *buf)
|
2005-04-26 22:53:22 +02:00
|
|
|
{
|
|
|
|
/* There must be string_len bytes in buf; write them onto string,
|
|
|
|
* then memmove buf back (that is, remove them from buf).
|
|
|
|
*
|
|
|
|
* Return the number of bytes still on the buffer. */
|
|
|
|
|
2005-04-27 02:53:44 +02:00
|
|
|
check();
|
2005-04-26 22:53:22 +02:00
|
|
|
peek_from_buf(string, string_len, buf);
|
2003-10-14 03:34:31 +02:00
|
|
|
buf_remove_from_front(buf, string_len);
|
2005-04-27 02:53:44 +02:00
|
|
|
check();
|
2008-02-22 04:44:36 +01:00
|
|
|
tor_assert(buf->datalen < INT_MAX);
|
|
|
|
return (int)buf->datalen;
|
2002-06-27 00:45:49 +02:00
|
|
|
}
|
|
|
|
|
2008-02-08 22:13:15 +01:00
|
|
|
/** Check <b>buf</b> for a variable-length cell according to the rules of link
|
|
|
|
* protocol version <b>linkproto</b>. If one is found, pull it off the buffer
|
|
|
|
* and assign a newly allocated var_cell_t to *<b>out</b>, and return 1.
|
|
|
|
* Return 0 if whatever is on the start of buf_t is not a variable-length
|
|
|
|
* cell. Return 1 and set *<b>out</b> to NULL if there seems to be the start
|
|
|
|
* of a variable-length cell on <b>buf</b>, but the whole thing isn't there
|
|
|
|
* yet. */
|
2007-11-05 22:46:35 +01:00
|
|
|
int
|
2008-02-08 22:13:15 +01:00
|
|
|
fetch_var_cell_from_buf(buf_t *buf, var_cell_t **out, int linkproto)
|
2007-11-05 22:46:35 +01:00
|
|
|
{
|
|
|
|
char hdr[VAR_CELL_HEADER_SIZE];
|
|
|
|
var_cell_t *result;
|
|
|
|
uint8_t command;
|
|
|
|
uint16_t length;
|
2008-02-08 22:13:15 +01:00
|
|
|
/* If linkproto is unknown (0) or v2 (2), variable-length cells work as
|
|
|
|
* implemented here. If it's 1, there are no variable-length cells. Tor
|
|
|
|
* does not support other versions right now, and so can't negotiate them.
|
|
|
|
*/
|
|
|
|
if (linkproto == 1)
|
|
|
|
return 0;
|
2007-11-05 22:46:35 +01:00
|
|
|
check();
|
|
|
|
*out = NULL;
|
|
|
|
if (buf->datalen < VAR_CELL_HEADER_SIZE)
|
|
|
|
return 0;
|
|
|
|
peek_from_buf(hdr, sizeof(hdr), buf);
|
|
|
|
|
2008-11-12 15:41:44 +01:00
|
|
|
command = get_uint8(hdr+2);
|
2007-11-05 22:46:35 +01:00
|
|
|
if (!(CELL_COMMAND_IS_VAR_LENGTH(command)))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
length = ntohs(get_uint16(hdr+3));
|
|
|
|
if (buf->datalen < (size_t)(VAR_CELL_HEADER_SIZE+length))
|
|
|
|
return 1;
|
2007-11-06 00:34:39 +01:00
|
|
|
result = var_cell_new(length);
|
2007-11-05 22:46:35 +01:00
|
|
|
result->command = command;
|
2008-11-12 15:41:44 +01:00
|
|
|
result->circ_id = ntohs(get_uint16(hdr));
|
2007-11-05 22:46:35 +01:00
|
|
|
|
|
|
|
buf_remove_from_front(buf, VAR_CELL_HEADER_SIZE);
|
|
|
|
peek_from_buf(result->payload, length, buf);
|
|
|
|
buf_remove_from_front(buf, length);
|
|
|
|
check();
|
|
|
|
|
|
|
|
*out = result;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2009-07-31 20:51:04 +02:00
|
|
|
#ifdef USE_BUFFEREVENTS
|
2009-08-11 23:01:36 +02:00
|
|
|
/** Try to read <b>n</b> bytes from <b>buf</b> at <b>pos</b> (which may be
|
2010-04-04 03:34:42 +02:00
|
|
|
* NULL for the start of the buffer), copying the data only if necessary. Set
|
2009-08-11 23:01:36 +02:00
|
|
|
* *<b>data</b> to a pointer to the desired bytes. Set <b>free_out</b> to 1
|
|
|
|
* if we needed to malloc *<b>data</b> because the original bytes were
|
|
|
|
* noncontiguous; 0 otherwise. Return the number of bytes actually available
|
|
|
|
* at <b>data</b>.
|
|
|
|
*/
|
2010-04-10 00:45:08 +02:00
|
|
|
static ssize_t
|
2009-08-11 22:56:09 +02:00
|
|
|
inspect_evbuffer(struct evbuffer *buf, char **data, size_t n, int *free_out,
|
|
|
|
struct evbuffer_ptr *pos)
|
2009-07-31 20:51:04 +02:00
|
|
|
{
|
|
|
|
int n_vecs, i;
|
|
|
|
|
|
|
|
if (evbuffer_get_length(buf) < n)
|
|
|
|
n = evbuffer_get_length(buf);
|
|
|
|
if (n == 0)
|
|
|
|
return 0;
|
2009-08-11 22:56:09 +02:00
|
|
|
n_vecs = evbuffer_peek(buf, n, pos, NULL, 0);
|
2010-04-10 00:45:08 +02:00
|
|
|
tor_assert(n_vecs > 0);
|
2009-07-31 20:51:04 +02:00
|
|
|
if (n_vecs == 1) {
|
|
|
|
struct evbuffer_iovec v;
|
2009-08-11 22:56:09 +02:00
|
|
|
i = evbuffer_peek(buf, n, pos, &v, 1);
|
2009-07-31 20:51:04 +02:00
|
|
|
tor_assert(i == 1);
|
|
|
|
*data = v.iov_base;
|
|
|
|
*free_out = 0;
|
|
|
|
return v.iov_len;
|
|
|
|
} else {
|
|
|
|
struct evbuffer_iovec *vecs =
|
|
|
|
tor_malloc(sizeof(struct evbuffer_iovec)*n_vecs);
|
|
|
|
size_t copied = 0;
|
|
|
|
i = evbuffer_peek(buf, n, NULL, vecs, n_vecs);
|
|
|
|
tor_assert(i == n_vecs);
|
|
|
|
*data = tor_malloc(n);
|
|
|
|
for (i=0; i < n_vecs; ++i) {
|
|
|
|
size_t copy = n - copied;
|
|
|
|
if (copy > vecs[i].iov_len)
|
|
|
|
copy = vecs[i].iov_len;
|
|
|
|
tor_assert(copied+copy <= n);
|
|
|
|
memcpy(data+copied, vecs[i].iov_base, copy);
|
|
|
|
copied += copy;
|
|
|
|
}
|
2010-04-10 00:45:08 +02:00
|
|
|
*free_out = 1;
|
2009-07-31 20:51:04 +02:00
|
|
|
return copied;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** As fetch_var_cell_from_buf, buf works on an evbuffer. */
|
|
|
|
int
|
|
|
|
fetch_var_cell_from_evbuffer(struct evbuffer *buf, var_cell_t **out,
|
|
|
|
int linkproto)
|
|
|
|
{
|
|
|
|
char *hdr = NULL;
|
|
|
|
int free_hdr = 0;
|
|
|
|
size_t n;
|
|
|
|
size_t buf_len;
|
|
|
|
uint8_t command;
|
|
|
|
uint16_t cell_length;
|
|
|
|
var_cell_t *cell;
|
2010-04-10 00:45:08 +02:00
|
|
|
int result = 0;
|
2009-07-31 20:51:04 +02:00
|
|
|
if (linkproto == 1)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
*out = NULL;
|
|
|
|
buf_len = evbuffer_get_length(buf);
|
2010-04-10 00:45:08 +02:00
|
|
|
if (buf_len < VAR_CELL_HEADER_SIZE)
|
|
|
|
return 0;
|
|
|
|
|
2009-08-11 22:56:09 +02:00
|
|
|
n = inspect_evbuffer(buf, &hdr, VAR_CELL_HEADER_SIZE, &free_hdr, NULL);
|
2009-08-14 20:34:16 +02:00
|
|
|
tor_assert(n >= VAR_CELL_HEADER_SIZE);
|
2009-07-31 20:51:04 +02:00
|
|
|
|
|
|
|
command = get_uint8(hdr+2);
|
|
|
|
if (!(CELL_COMMAND_IS_VAR_LENGTH(command))) {
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
cell_length = ntohs(get_uint16(hdr+3));
|
|
|
|
if (buf_len < (size_t)(VAR_CELL_HEADER_SIZE+cell_length)) {
|
|
|
|
result = 1; /* Not all here yet. */
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
cell = var_cell_new(cell_length);
|
|
|
|
cell->command = command;
|
|
|
|
cell->circ_id = ntohs(get_uint16(hdr));
|
|
|
|
evbuffer_drain(buf, VAR_CELL_HEADER_SIZE);
|
|
|
|
evbuffer_remove(buf, cell->payload, cell_length);
|
|
|
|
*out = cell;
|
|
|
|
result = 1;
|
|
|
|
|
|
|
|
done:
|
|
|
|
if (free_hdr && hdr)
|
|
|
|
tor_free(hdr);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-04-25 09:20:04 +02:00
|
|
|
/** Move up to *<b>buf_flushlen</b> bytes from <b>buf_in</b> to
|
|
|
|
* <b>buf_out</b>, and modify *<b>buf_flushlen</b> appropriately.
|
2007-04-21 19:26:12 +02:00
|
|
|
* Return the number of bytes actually copied.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
move_buf_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen)
|
|
|
|
{
|
2010-10-15 17:38:33 +02:00
|
|
|
/* We can do way better here, but this doesn't turn up in any profiles. */
|
2007-04-21 19:26:12 +02:00
|
|
|
char b[4096];
|
|
|
|
size_t cp, len;
|
|
|
|
len = *buf_flushlen;
|
|
|
|
if (len > buf_in->datalen)
|
|
|
|
len = buf_in->datalen;
|
|
|
|
|
|
|
|
cp = len; /* Remember the number of bytes we intend to copy. */
|
2008-02-22 04:44:36 +01:00
|
|
|
tor_assert(cp < INT_MAX);
|
2007-04-21 19:26:12 +02:00
|
|
|
while (len) {
|
|
|
|
/* This isn't the most efficient implementation one could imagine, since
|
|
|
|
* it does two copies instead of 1, but I kinda doubt that this will be
|
|
|
|
* critical path. */
|
|
|
|
size_t n = len > sizeof(b) ? sizeof(b) : len;
|
|
|
|
fetch_from_buf(b, n, buf_in);
|
|
|
|
write_to_buf(b, n, buf_out);
|
|
|
|
len -= n;
|
|
|
|
}
|
|
|
|
*buf_flushlen -= cp;
|
2008-02-22 04:44:36 +01:00
|
|
|
return (int)cp;
|
2007-04-21 19:26:12 +02:00
|
|
|
}
|
|
|
|
|
2007-12-30 01:13:07 +01:00
|
|
|
/** Internal structure: represents a position in a buffer. */
|
2007-12-29 18:36:03 +01:00
|
|
|
typedef struct buf_pos_t {
|
2007-12-30 01:13:07 +01:00
|
|
|
const chunk_t *chunk; /**< Which chunk are we pointing to? */
|
2008-02-21 22:15:31 +01:00
|
|
|
int pos;/**< Which character inside the chunk's data are we pointing to? */
|
2008-02-20 18:48:39 +01:00
|
|
|
size_t chunk_pos; /**< Total length of all previous chunks. */
|
2007-12-30 01:13:07 +01:00
|
|
|
} buf_pos_t;
|
2007-12-29 18:36:03 +01:00
|
|
|
|
2007-12-30 01:13:07 +01:00
|
|
|
/** Initialize <b>out</b> to point to the first character of <b>buf</b>.*/
|
2007-12-29 18:36:03 +01:00
|
|
|
static void
|
2007-12-30 01:13:07 +01:00
|
|
|
buf_pos_init(const buf_t *buf, buf_pos_t *out)
|
2007-12-29 18:36:03 +01:00
|
|
|
{
|
|
|
|
out->chunk = buf->head;
|
|
|
|
out->pos = 0;
|
2008-02-20 18:48:39 +01:00
|
|
|
out->chunk_pos = 0;
|
2007-12-29 18:36:03 +01:00
|
|
|
}
|
|
|
|
|
2007-12-30 01:13:07 +01:00
|
|
|
/** Advance <b>out</b> to the first appearance of <b>ch</b> at the current
|
|
|
|
* position of <b>out</b>, or later. Return -1 if no instances are found;
|
|
|
|
* otherwise returns the absolute position of the character. */
|
2008-02-22 04:44:36 +01:00
|
|
|
static off_t
|
2007-12-30 01:13:07 +01:00
|
|
|
buf_find_pos_of_char(char ch, buf_pos_t *out)
|
2007-12-29 18:36:03 +01:00
|
|
|
{
|
2007-12-30 01:13:07 +01:00
|
|
|
const chunk_t *chunk;
|
2008-02-20 17:57:39 +01:00
|
|
|
int pos;
|
2008-02-20 18:48:39 +01:00
|
|
|
tor_assert(out);
|
2008-02-21 00:38:57 +01:00
|
|
|
if (out->chunk) {
|
2008-02-21 00:58:48 +01:00
|
|
|
if (out->chunk->datalen) {
|
|
|
|
tor_assert(out->pos < (off_t)out->chunk->datalen);
|
|
|
|
} else {
|
|
|
|
tor_assert(out->pos == 0);
|
2008-02-21 00:38:57 +01:00
|
|
|
}
|
|
|
|
}
|
2008-02-20 17:57:39 +01:00
|
|
|
pos = out->pos;
|
2007-12-29 18:36:03 +01:00
|
|
|
for (chunk = out->chunk; chunk; chunk = chunk->next) {
|
2008-02-21 22:15:31 +01:00
|
|
|
char *cp = memchr(chunk->data+pos, ch, chunk->datalen - pos);
|
2007-12-29 18:36:03 +01:00
|
|
|
if (cp) {
|
|
|
|
out->chunk = chunk;
|
2008-02-22 04:44:36 +01:00
|
|
|
tor_assert(cp - chunk->data < INT_MAX);
|
|
|
|
out->pos = (int)(cp - chunk->data);
|
2008-02-20 18:48:39 +01:00
|
|
|
return out->chunk_pos + out->pos;
|
2007-12-29 18:36:03 +01:00
|
|
|
} else {
|
2008-02-20 18:48:39 +01:00
|
|
|
out->chunk_pos += chunk->datalen;
|
2007-12-29 18:36:03 +01:00
|
|
|
pos = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-12-30 01:13:07 +01:00
|
|
|
/** Advance <b>pos</b> by a single character, if there are any more characters
|
2009-05-27 23:55:51 +02:00
|
|
|
* in the buffer. Returns 0 on success, -1 on failure. */
|
2007-12-29 18:36:03 +01:00
|
|
|
static INLINE int
|
|
|
|
buf_pos_inc(buf_pos_t *pos)
|
|
|
|
{
|
2008-02-20 18:48:39 +01:00
|
|
|
++pos->pos;
|
2008-02-20 22:57:48 +01:00
|
|
|
if (pos->pos == (off_t)pos->chunk->datalen) {
|
2007-12-29 18:36:03 +01:00
|
|
|
if (!pos->chunk->next)
|
|
|
|
return -1;
|
2008-02-20 18:48:39 +01:00
|
|
|
pos->chunk_pos += pos->chunk->datalen;
|
2007-12-29 18:36:03 +01:00
|
|
|
pos->chunk = pos->chunk->next;
|
|
|
|
pos->pos = 0;
|
|
|
|
}
|
2007-12-30 01:13:07 +01:00
|
|
|
return 0;
|
2007-12-29 18:36:03 +01:00
|
|
|
}
|
|
|
|
|
2007-12-30 01:13:07 +01:00
|
|
|
/** Return true iff the <b>n</b>-character string in <b>s</b> appears
|
|
|
|
* (verbatim) at <b>pos</b>. */
|
2007-12-29 18:36:03 +01:00
|
|
|
static int
|
2008-02-19 23:52:50 +01:00
|
|
|
buf_matches_at_pos(const buf_pos_t *pos, const char *s, size_t n)
|
2007-12-29 18:36:03 +01:00
|
|
|
{
|
|
|
|
buf_pos_t p;
|
2008-02-21 03:10:38 +01:00
|
|
|
if (!n)
|
|
|
|
return 1;
|
|
|
|
|
2007-12-30 01:13:07 +01:00
|
|
|
memcpy(&p, pos, sizeof(p));
|
2007-12-29 18:36:03 +01:00
|
|
|
|
2008-02-21 03:10:38 +01:00
|
|
|
while (1) {
|
2007-12-30 01:13:07 +01:00
|
|
|
char ch = p.chunk->data[p.pos];
|
2007-12-29 18:36:03 +01:00
|
|
|
if (ch != *s)
|
|
|
|
return 0;
|
|
|
|
++s;
|
2008-02-21 03:10:38 +01:00
|
|
|
/* If we're out of characters that don't match, we match. Check this
|
|
|
|
* _before_ we test incrementing pos, in case we're at the end of the
|
|
|
|
* string. */
|
|
|
|
if (--n == 0)
|
|
|
|
return 1;
|
2007-12-30 01:13:07 +01:00
|
|
|
if (buf_pos_inc(&p)<0)
|
2007-12-29 18:36:03 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-12-30 01:13:07 +01:00
|
|
|
/** Return the first position in <b>buf</b> at which the <b>n</b>-character
|
|
|
|
* string <b>s</b> occurs, or -1 if it does not occur. */
|
2008-02-21 00:20:36 +01:00
|
|
|
/*private*/ int
|
2008-02-19 23:52:50 +01:00
|
|
|
buf_find_string_offset(const buf_t *buf, const char *s, size_t n)
|
2007-12-29 18:36:03 +01:00
|
|
|
{
|
|
|
|
buf_pos_t pos;
|
|
|
|
buf_pos_init(buf, &pos);
|
2007-12-30 01:13:07 +01:00
|
|
|
while (buf_find_pos_of_char(*s, &pos) >= 0) {
|
|
|
|
if (buf_matches_at_pos(&pos, s, n)) {
|
2008-02-22 04:44:36 +01:00
|
|
|
tor_assert(pos.chunk_pos + pos.pos < INT_MAX);
|
|
|
|
return (int)(pos.chunk_pos + pos.pos);
|
2007-12-29 18:36:03 +01:00
|
|
|
} else {
|
2007-12-30 01:13:07 +01:00
|
|
|
if (buf_pos_inc(&pos)<0)
|
2007-12-29 18:36:03 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/** There is a (possibly incomplete) http statement on <b>buf</b>, of the
|
2009-05-27 23:55:51 +02:00
|
|
|
* form "\%s\\r\\n\\r\\n\%s", headers, body. (body may contain NULs.)
|
2003-09-17 22:09:06 +02:00
|
|
|
* If a) the headers include a Content-Length field and all bytes in
|
|
|
|
* the body are present, or b) there's no Content-Length field and
|
|
|
|
* all headers are present, then:
|
2004-03-31 07:01:30 +02:00
|
|
|
*
|
2009-05-27 23:55:51 +02:00
|
|
|
* - strdup headers into <b>*headers_out</b>, and NUL-terminate it.
|
|
|
|
* - memdup body into <b>*body_out</b>, and NUL-terminate it.
|
2004-05-09 18:47:25 +02:00
|
|
|
* - Then remove them from <b>buf</b>, and return 1.
|
2004-05-07 19:04:12 +02:00
|
|
|
*
|
|
|
|
* - If headers or body is NULL, discard that part of the buf.
|
|
|
|
* - If a headers or body doesn't fit in the arg, return -1.
|
2004-10-12 22:22:09 +02:00
|
|
|
* (We ensure that the headers or body don't exceed max len,
|
|
|
|
* _even if_ we're planning to discard them.)
|
2005-10-14 04:26:13 +02:00
|
|
|
* - If force_complete is true, then succeed even if not all of the
|
|
|
|
* content has arrived.
|
2003-12-17 22:09:31 +01:00
|
|
|
*
|
2003-09-17 22:09:06 +02:00
|
|
|
* Else, change nothing and return 0.
|
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
|
|
|
fetch_from_buf_http(buf_t *buf,
|
|
|
|
char **headers_out, size_t max_headerlen,
|
2005-10-14 04:26:13 +02:00
|
|
|
char **body_out, size_t *body_used, size_t max_bodylen,
|
|
|
|
int force_complete)
|
2005-06-11 20:52:12 +02:00
|
|
|
{
|
2007-12-30 01:13:07 +01:00
|
|
|
char *headers, *p;
|
2004-10-14 04:47:09 +02:00
|
|
|
size_t headerlen, bodylen, contentlen;
|
2007-12-29 18:36:03 +01:00
|
|
|
int crlf_offset;
|
2003-09-17 22:09:06 +02:00
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
check();
|
|
|
|
if (!buf->head)
|
|
|
|
return 0;
|
2003-09-17 22:09:06 +02:00
|
|
|
|
2007-12-29 18:36:03 +01:00
|
|
|
crlf_offset = buf_find_string_offset(buf, "\r\n\r\n", 4);
|
2007-12-30 01:13:07 +01:00
|
|
|
if (crlf_offset > (int)max_headerlen ||
|
2007-12-29 18:36:03 +01:00
|
|
|
(crlf_offset < 0 && buf->datalen > max_headerlen)) {
|
|
|
|
log_debug(LD_HTTP,"headers too long.");
|
|
|
|
return -1;
|
|
|
|
} else if (crlf_offset < 0) {
|
|
|
|
log_debug(LD_HTTP,"headers not all here yet.");
|
|
|
|
return 0;
|
|
|
|
}
|
2007-12-30 01:13:07 +01:00
|
|
|
/* Okay, we have a full header. Make sure it all appears in the first
|
|
|
|
* chunk. */
|
|
|
|
if ((int)buf->head->datalen < crlf_offset + 4)
|
2007-12-29 18:36:03 +01:00
|
|
|
buf_pullup(buf, crlf_offset+4, 0);
|
|
|
|
headerlen = crlf_offset + 4;
|
|
|
|
|
2008-02-21 03:10:38 +01:00
|
|
|
headers = buf->head->data;
|
2003-09-25 07:17:11 +02:00
|
|
|
bodylen = buf->datalen - headerlen;
|
2006-02-13 09:28:42 +01:00
|
|
|
log_debug(LD_HTTP,"headerlen %d, bodylen %d.", (int)headerlen, (int)bodylen);
|
2003-09-17 22:09:06 +02:00
|
|
|
|
2004-11-28 10:05:49 +01:00
|
|
|
if (max_headerlen <= headerlen) {
|
2006-02-13 09:28:42 +01:00
|
|
|
log_warn(LD_HTTP,"headerlen %d larger than %d. Failing.",
|
|
|
|
(int)headerlen, (int)max_headerlen-1);
|
2003-09-17 22:09:06 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2004-11-28 10:05:49 +01:00
|
|
|
if (max_bodylen <= bodylen) {
|
2006-02-13 09:28:42 +01:00
|
|
|
log_warn(LD_HTTP,"bodylen %d larger than %d. Failing.",
|
|
|
|
(int)bodylen, (int)max_bodylen-1);
|
2003-09-17 22:09:06 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2003-09-21 08:15:43 +02:00
|
|
|
#define CONTENT_LENGTH "\r\nContent-Length: "
|
2007-12-29 18:36:03 +01:00
|
|
|
p = (char*) tor_memstr(headers, headerlen, CONTENT_LENGTH);
|
2004-05-18 17:35:21 +02:00
|
|
|
if (p) {
|
2004-10-14 04:47:09 +02:00
|
|
|
int i;
|
|
|
|
i = atoi(p+strlen(CONTENT_LENGTH));
|
|
|
|
if (i < 0) {
|
2006-02-13 09:28:42 +01:00
|
|
|
log_warn(LD_PROTOCOL, "Content-Length is less than zero; it looks like "
|
|
|
|
"someone is trying to crash us.");
|
2004-10-12 20:38:36 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2004-10-14 04:47:09 +02:00
|
|
|
contentlen = i;
|
2004-03-31 07:01:30 +02:00
|
|
|
/* if content-length is malformed, then our body length is 0. fine. */
|
2006-02-13 09:28:42 +01:00
|
|
|
log_debug(LD_HTTP,"Got a contentlen of %d.",(int)contentlen);
|
2004-11-28 10:05:49 +01:00
|
|
|
if (bodylen < contentlen) {
|
2005-10-14 04:26:13 +02:00
|
|
|
if (!force_complete) {
|
2006-02-13 09:28:42 +01:00
|
|
|
log_debug(LD_HTTP,"body not all here yet.");
|
2005-10-14 04:26:13 +02:00
|
|
|
return 0; /* not all there yet */
|
|
|
|
}
|
2003-09-17 22:09:06 +02:00
|
|
|
}
|
2004-11-28 10:05:49 +01:00
|
|
|
if (bodylen > contentlen) {
|
2004-04-26 23:15:06 +02:00
|
|
|
bodylen = contentlen;
|
2006-02-13 09:28:42 +01:00
|
|
|
log_debug(LD_HTTP,"bodylen reduced to %d.",(int)bodylen);
|
2004-04-26 23:15:06 +02:00
|
|
|
}
|
2003-09-17 22:09:06 +02:00
|
|
|
}
|
|
|
|
/* all happy. copy into the appropriate places, and return 1 */
|
2004-11-28 10:05:49 +01:00
|
|
|
if (headers_out) {
|
2003-12-17 10:42:28 +01:00
|
|
|
*headers_out = tor_malloc(headerlen+1);
|
2007-12-26 01:12:08 +01:00
|
|
|
fetch_from_buf(*headers_out, headerlen, buf);
|
2009-05-27 23:55:51 +02:00
|
|
|
(*headers_out)[headerlen] = 0; /* NUL terminate it */
|
2003-09-17 22:09:06 +02:00
|
|
|
}
|
2004-11-28 10:05:49 +01:00
|
|
|
if (body_out) {
|
2004-04-25 22:37:37 +02:00
|
|
|
tor_assert(body_used);
|
2004-03-31 07:01:30 +02:00
|
|
|
*body_used = bodylen;
|
2003-12-17 10:42:28 +01:00
|
|
|
*body_out = tor_malloc(bodylen+1);
|
2007-12-26 01:12:08 +01:00
|
|
|
fetch_from_buf(*body_out, bodylen, buf);
|
2009-05-27 23:55:51 +02:00
|
|
|
(*body_out)[bodylen] = 0; /* NUL terminate it */
|
2003-09-17 22:09:06 +02:00
|
|
|
}
|
2007-12-26 01:12:08 +01:00
|
|
|
check();
|
2003-09-17 22:09:06 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2009-08-04 18:44:30 +02:00
|
|
|
#ifdef USE_BUFFEREVENTS
|
2010-04-04 03:34:42 +02:00
|
|
|
/** As fetch_from_buf_http, buf works on an evbuffer. */
|
2009-08-04 18:44:30 +02:00
|
|
|
int
|
|
|
|
fetch_from_evbuffer_http(struct evbuffer *buf,
|
|
|
|
char **headers_out, size_t max_headerlen,
|
|
|
|
char **body_out, size_t *body_used, size_t max_bodylen,
|
|
|
|
int force_complete)
|
|
|
|
{
|
2009-08-11 22:56:09 +02:00
|
|
|
struct evbuffer_ptr crlf, content_length;
|
2009-08-04 18:44:30 +02:00
|
|
|
size_t headerlen, bodylen, contentlen;
|
|
|
|
|
2010-04-10 00:45:08 +02:00
|
|
|
/* Find the first \r\n\r\n in the buffer */
|
2009-08-04 18:44:30 +02:00
|
|
|
crlf = evbuffer_search(buf, "\r\n\r\n", 4, NULL);
|
|
|
|
if (crlf.pos < 0) {
|
2010-04-10 00:45:08 +02:00
|
|
|
/* We didn't find one. */
|
2009-08-04 18:44:30 +02:00
|
|
|
if (evbuffer_get_length(buf) > max_headerlen)
|
|
|
|
return -1; /* Headers too long. */
|
|
|
|
return 0; /* Headers not here yet. */
|
2010-04-10 00:45:08 +02:00
|
|
|
} else if (crlf.pos > (int)max_headerlen) {
|
2009-08-04 18:44:30 +02:00
|
|
|
return -1; /* Headers too long. */
|
2010-04-10 00:45:08 +02:00
|
|
|
}
|
2009-08-04 18:44:30 +02:00
|
|
|
|
2010-04-10 00:45:08 +02:00
|
|
|
headerlen = crlf.pos + 4; /* Skip over the \r\n\r\n */
|
2009-08-04 18:44:30 +02:00
|
|
|
bodylen = evbuffer_get_length(buf) - headerlen;
|
|
|
|
if (bodylen > max_bodylen)
|
|
|
|
return -1; /* body too long */
|
|
|
|
|
2010-04-10 00:45:08 +02:00
|
|
|
/* Look for the first occurrence of CONTENT_LENGTH insize buf before the
|
|
|
|
* crlfcrlf */
|
2009-08-11 22:56:09 +02:00
|
|
|
content_length = evbuffer_search_range(buf, CONTENT_LENGTH,
|
|
|
|
strlen(CONTENT_LENGTH), NULL, &crlf);
|
|
|
|
|
|
|
|
if (content_length.pos >= 0) {
|
2010-04-10 00:45:08 +02:00
|
|
|
/* We found a content_length: parse it and figure out if the body is here
|
|
|
|
* yet. */
|
2009-08-11 22:56:09 +02:00
|
|
|
struct evbuffer_ptr eol;
|
|
|
|
char *data = NULL;
|
|
|
|
int free_data = 0;
|
|
|
|
int n, i;
|
|
|
|
n = evbuffer_ptr_set(buf, &content_length, strlen(CONTENT_LENGTH),
|
|
|
|
EVBUFFER_PTR_ADD);
|
|
|
|
tor_assert(n == 0);
|
|
|
|
eol = evbuffer_search_eol(buf, &content_length, NULL, EVBUFFER_EOL_CRLF);
|
|
|
|
tor_assert(eol.pos > content_length.pos);
|
|
|
|
tor_assert(eol.pos <= crlf.pos);
|
|
|
|
inspect_evbuffer(buf, &data, eol.pos - content_length.pos, &free_data,
|
|
|
|
&content_length);
|
|
|
|
|
|
|
|
i = atoi(data);
|
|
|
|
if (free_data)
|
|
|
|
tor_free(data);
|
2009-08-04 18:44:30 +02:00
|
|
|
if (i < 0) {
|
|
|
|
log_warn(LD_PROTOCOL, "Content-Length is less than zero; it looks like "
|
|
|
|
"someone is trying to crash us.");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
contentlen = i;
|
|
|
|
/* if content-length is malformed, then our body length is 0. fine. */
|
|
|
|
log_debug(LD_HTTP,"Got a contentlen of %d.",(int)contentlen);
|
|
|
|
if (bodylen < contentlen) {
|
|
|
|
if (!force_complete) {
|
|
|
|
log_debug(LD_HTTP,"body not all here yet.");
|
|
|
|
return 0; /* not all there yet */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (bodylen > contentlen) {
|
|
|
|
bodylen = contentlen;
|
|
|
|
log_debug(LD_HTTP,"bodylen reduced to %d.",(int)bodylen);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (headers_out) {
|
|
|
|
*headers_out = tor_malloc(headerlen+1);
|
|
|
|
evbuffer_remove(buf, *headers_out, headerlen);
|
|
|
|
(*headers_out)[headerlen] = '\0';
|
|
|
|
}
|
|
|
|
if (body_out) {
|
|
|
|
tor_assert(headers_out);
|
|
|
|
tor_assert(body_used);
|
|
|
|
*body_used = bodylen;
|
|
|
|
*body_out = tor_malloc(bodylen+1);
|
|
|
|
evbuffer_remove(buf, *body_out, bodylen);
|
|
|
|
(*body_out)[bodylen] = '\0';
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2010-10-04 13:31:58 +02:00
|
|
|
/**
|
|
|
|
* Wait this many seconds before warning the user about using SOCKS unsafely
|
|
|
|
* again (requires that WarnUnsafeSocks is turned on). */
|
|
|
|
#define SOCKS_WARN_INTERVAL 5
|
|
|
|
|
|
|
|
/** Warn that the user application has made an unsafe socks request using
|
|
|
|
* protocol <b>socks_protocol</b> on port <b>port</b>. Don't warn more than
|
|
|
|
* once per SOCKS_WARN_INTERVAL, unless <b>safe_socks</b> is set. */
|
|
|
|
static void
|
2010-11-15 21:41:21 +01:00
|
|
|
log_unsafe_socks_warning(int socks_protocol, const char *address,
|
|
|
|
uint16_t port, int safe_socks)
|
2010-10-04 13:31:58 +02:00
|
|
|
{
|
|
|
|
static ratelim_t socks_ratelim = RATELIM_INIT(SOCKS_WARN_INTERVAL);
|
|
|
|
|
|
|
|
or_options_t *options = get_options();
|
|
|
|
char *m = NULL;
|
|
|
|
if (! options->WarnUnsafeSocks)
|
|
|
|
return;
|
|
|
|
if (safe_socks || (m = rate_limit_log(&socks_ratelim, approx_time()))) {
|
|
|
|
log_warn(LD_APP,
|
|
|
|
"Your application (using socks%d to port %d) is giving "
|
|
|
|
"Tor only an IP address. Applications that do DNS resolves "
|
|
|
|
"themselves may leak information. Consider using Socks4A "
|
|
|
|
"(e.g. via privoxy or socat) instead. For more information, "
|
|
|
|
"please see https://wiki.torproject.org/TheOnionRouter/"
|
|
|
|
"TorFAQ#SOCKSAndDNS.%s%s",
|
|
|
|
socks_protocol,
|
|
|
|
(int)port,
|
|
|
|
safe_socks ? " Rejecting." : "",
|
|
|
|
m ? m : "");
|
|
|
|
tor_free(m);
|
|
|
|
}
|
2010-11-15 21:41:21 +01:00
|
|
|
control_event_client_status(LOG_WARN,
|
|
|
|
"DANGEROUS_SOCKS PROTOCOL=SOCKS%d ADDRESS=%s:%d",
|
|
|
|
socks_protocol, address, (int)port);
|
2010-10-04 13:31:58 +02:00
|
|
|
}
|
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/** There is a (possibly incomplete) socks handshake on <b>buf</b>, of one
|
2003-10-04 03:37:01 +02:00
|
|
|
* of the forms
|
2004-05-07 19:04:12 +02:00
|
|
|
* - socks4: "socksheader username\\0"
|
|
|
|
* - socks4a: "socksheader username\\0 destaddr\\0"
|
|
|
|
* - socks5 phase one: "version #methods methods"
|
|
|
|
* - socks5 phase two: "version command 0 addresstype..."
|
2003-11-11 03:41:31 +01:00
|
|
|
* If it's a complete and valid handshake, and destaddr fits in
|
|
|
|
* MAX_SOCKS_ADDR_LEN bytes, then pull the handshake off the buf,
|
2004-05-09 18:47:25 +02:00
|
|
|
* assign to <b>req</b>, and return 1.
|
2004-05-07 19:04:12 +02:00
|
|
|
*
|
2003-09-18 10:11:31 +02:00
|
|
|
* If it's invalid or too big, return -1.
|
2004-05-07 19:04:12 +02:00
|
|
|
*
|
2003-10-04 03:37:01 +02:00
|
|
|
* Else it's not all there yet, leave buf alone and return 0.
|
2004-05-07 19:04:12 +02:00
|
|
|
*
|
2004-05-09 18:47:25 +02:00
|
|
|
* If you want to specify the socks reply, write it into <b>req->reply</b>
|
|
|
|
* and set <b>req->replylen</b>, else leave <b>req->replylen</b> alone.
|
2004-05-07 19:04:12 +02:00
|
|
|
*
|
2005-11-17 00:37:35 +01:00
|
|
|
* If <b>log_sockstype</b> is non-zero, then do a notice-level log of whether
|
|
|
|
* the connection is possibly leaking DNS requests locally or not.
|
|
|
|
*
|
2006-03-19 02:44:53 +01:00
|
|
|
* If <b>safe_socks</b> is true, then reject unsafe socks protocols.
|
|
|
|
*
|
2005-12-14 21:40:40 +01:00
|
|
|
* If returning 0 or -1, <b>req->address</b> and <b>req->port</b> are
|
|
|
|
* undefined.
|
2003-09-18 10:11:31 +02:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
2006-03-19 02:44:53 +01:00
|
|
|
fetch_from_buf_socks(buf_t *buf, socks_request_t *req,
|
|
|
|
int log_sockstype, int safe_socks)
|
2009-07-31 23:03:35 +02:00
|
|
|
{
|
|
|
|
int res;
|
|
|
|
ssize_t n_drain;
|
|
|
|
size_t want_length = 128;
|
|
|
|
|
|
|
|
if (buf->datalen < 2) /* version and another byte */
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
do {
|
|
|
|
n_drain = 0;
|
|
|
|
buf_pullup(buf, want_length, 0);
|
|
|
|
tor_assert(buf->head && buf->head->datalen >= 2);
|
|
|
|
want_length = 0;
|
|
|
|
|
|
|
|
res = parse_socks(buf->head->data, buf->head->datalen, req, log_sockstype,
|
|
|
|
safe_socks, &n_drain, &want_length);
|
|
|
|
|
|
|
|
if (n_drain < 0)
|
|
|
|
buf_clear(buf);
|
|
|
|
else if (n_drain > 0)
|
|
|
|
buf_remove_from_front(buf, n_drain);
|
|
|
|
|
|
|
|
} while (res == 0 && buf->head &&
|
|
|
|
buf->datalen > buf->head->datalen &&
|
|
|
|
want_length < buf->head->datalen);
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef USE_BUFFEREVENTS
|
|
|
|
/* As fetch_from_buf_socks(), but targets an evbuffer instead. */
|
|
|
|
int
|
|
|
|
fetch_from_evbuffer_socks(struct evbuffer *buf, socks_request_t *req,
|
|
|
|
int log_sockstype, int safe_socks)
|
|
|
|
{
|
2009-08-11 23:44:43 +02:00
|
|
|
char *data;
|
2009-07-31 23:03:35 +02:00
|
|
|
ssize_t n_drain;
|
|
|
|
size_t datalen, buflen, want_length;
|
|
|
|
int res;
|
|
|
|
|
|
|
|
buflen = evbuffer_get_length(buf);
|
|
|
|
if (buflen < 2)
|
|
|
|
return 0;
|
|
|
|
|
2009-08-11 23:44:43 +02:00
|
|
|
{
|
2010-09-27 18:41:41 +02:00
|
|
|
/* See if we can find the socks request in the first chunk of the buffer.
|
|
|
|
*/
|
2009-08-11 23:44:43 +02:00
|
|
|
struct evbuffer_iovec v;
|
|
|
|
int i;
|
|
|
|
want_length = evbuffer_get_contiguous_space(buf);
|
|
|
|
n_drain = 0;
|
|
|
|
i = evbuffer_peek(buf, want_length, NULL, &v, 1);
|
2009-08-26 17:55:36 +02:00
|
|
|
tor_assert(i == 1);
|
2009-08-11 23:44:43 +02:00
|
|
|
data = v.iov_base;
|
|
|
|
datalen = v.iov_len;
|
2009-07-31 23:03:35 +02:00
|
|
|
|
2009-08-11 23:44:43 +02:00
|
|
|
res = parse_socks(data, datalen, req, log_sockstype,
|
|
|
|
safe_socks, &n_drain, &want_length);
|
|
|
|
|
|
|
|
if (n_drain < 0)
|
|
|
|
evbuffer_drain(buf, evbuffer_get_length(buf));
|
|
|
|
else if (n_drain > 0)
|
|
|
|
evbuffer_drain(buf, n_drain);
|
|
|
|
|
|
|
|
if (res)
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2010-04-10 00:45:08 +02:00
|
|
|
/* Okay, the first chunk of the buffer didn't have a complete socks request.
|
|
|
|
* That means that either we don't have a whole socks request at all, or
|
|
|
|
* it's gotten split up. We're going to try passing parse_socks() bigger
|
|
|
|
* and bigger chunks until either it says "Okay, I got it", or it says it
|
|
|
|
* will need more data than we currently have. */
|
|
|
|
|
|
|
|
/* Loop while we have more data that we haven't given parse_socks() yet. */
|
2009-08-11 23:44:43 +02:00
|
|
|
while (evbuffer_get_length(buf) > datalen) {
|
|
|
|
int free_data = 0;
|
2009-07-31 23:03:35 +02:00
|
|
|
n_drain = 0;
|
2009-08-11 23:44:43 +02:00
|
|
|
data = NULL;
|
|
|
|
datalen = inspect_evbuffer(buf, &data, want_length, &free_data, NULL);
|
2009-07-31 23:03:35 +02:00
|
|
|
|
|
|
|
res = parse_socks(data, datalen, req, log_sockstype,
|
|
|
|
safe_socks, &n_drain, &want_length);
|
|
|
|
|
2009-08-11 23:44:43 +02:00
|
|
|
if (free_data)
|
|
|
|
tor_free(data);
|
|
|
|
|
2009-07-31 23:03:35 +02:00
|
|
|
if (n_drain < 0)
|
|
|
|
evbuffer_drain(buf, evbuffer_get_length(buf));
|
|
|
|
else if (n_drain > 0)
|
|
|
|
evbuffer_drain(buf, n_drain);
|
|
|
|
|
2010-04-10 00:45:08 +02:00
|
|
|
if (res) /* If res is nonzero, parse_socks() made up its mind. */
|
2009-08-11 23:44:43 +02:00
|
|
|
return res;
|
2009-07-31 23:03:35 +02:00
|
|
|
|
2010-04-10 00:45:08 +02:00
|
|
|
/* If parse_socks says that we want less data than we actually tried to
|
|
|
|
give it, we've got some kind of weird situation; just exit the loop for
|
|
|
|
now.
|
|
|
|
*/
|
2009-08-11 23:44:43 +02:00
|
|
|
if (want_length <= datalen)
|
|
|
|
break;
|
2010-04-10 00:45:08 +02:00
|
|
|
/* Otherwise, it wants more data than we gave it. If we can provide more
|
|
|
|
* data than we gave it, we'll try to do so in the next iteration of the
|
2010-09-27 18:41:41 +02:00
|
|
|
* loop. If we can't, the while loop will exit. It's okay if it asked for
|
|
|
|
* more than we have total; maybe it doesn't really need so much. */
|
2009-08-11 23:44:43 +02:00
|
|
|
}
|
2009-07-31 23:03:35 +02:00
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/** Implementation helper to implement fetch_from_*_socks. Instead of looking
|
|
|
|
* at a buffer's contents, we look at the <b>datalen</b> bytes of data in
|
|
|
|
* <b>data</b>. Instead of removing data from the buffer, we set
|
|
|
|
* <b>drain_out</b> to the amount of data that should be removed (or -1 if the
|
2010-04-04 03:34:42 +02:00
|
|
|
* buffer should be cleared). Instead of pulling more data into the first
|
2009-07-31 23:03:35 +02:00
|
|
|
* chunk of the buffer, we set *<b>want_length_out</b> to the number of bytes
|
2010-04-10 00:45:08 +02:00
|
|
|
* we'd like to see in the input buffer, if they're available. */
|
2009-07-31 23:03:35 +02:00
|
|
|
static int
|
|
|
|
parse_socks(const char *data, size_t datalen, socks_request_t *req,
|
|
|
|
int log_sockstype, int safe_socks, ssize_t *drain_out,
|
|
|
|
size_t *want_length_out)
|
2005-06-11 20:52:12 +02:00
|
|
|
{
|
2007-05-15 23:17:48 +02:00
|
|
|
unsigned int len;
|
2008-08-08 18:41:59 +02:00
|
|
|
char tmpbuf[TOR_ADDR_BUF_LEN+1];
|
|
|
|
tor_addr_t destaddr;
|
2003-10-04 03:37:01 +02:00
|
|
|
uint32_t destip;
|
2007-12-26 01:12:08 +01:00
|
|
|
uint8_t socksver;
|
2003-10-04 03:37:01 +02:00
|
|
|
enum {socks4, socks4a} socks4_prot = socks4a;
|
2003-09-18 10:11:31 +02:00
|
|
|
char *next, *startaddr;
|
2010-08-03 23:28:55 +02:00
|
|
|
unsigned char usernamelen, passlen;
|
2003-10-04 03:37:01 +02:00
|
|
|
struct in_addr in;
|
2003-09-18 10:11:31 +02:00
|
|
|
|
2009-07-31 23:03:35 +02:00
|
|
|
socksver = *data;
|
2007-12-26 01:12:08 +01:00
|
|
|
|
|
|
|
switch (socksver) { /* which version of socks? */
|
2003-10-04 03:37:01 +02:00
|
|
|
|
2010-08-03 23:28:55 +02:00
|
|
|
case 1: /* socks5: username/password authentication request */
|
|
|
|
|
2010-10-17 15:14:51 +02:00
|
|
|
if (req->socks_version != 5) {
|
|
|
|
log_warn(LD_APP,
|
|
|
|
"socks5: Received authentication attempt before "
|
|
|
|
"authentication negotiated. Rejecting.");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
usernamelen = (unsigned char)*(data + 1);
|
|
|
|
if (datalen < 2u + usernamelen) {
|
|
|
|
*want_length_out = 2u+usernamelen;
|
2010-08-03 23:28:55 +02:00
|
|
|
return 0;
|
2010-10-17 15:14:51 +02:00
|
|
|
}
|
|
|
|
passlen = (unsigned char)*(data + 2u + usernamelen);
|
|
|
|
if (datalen < 2u + usernamelen + 1u + passlen) {
|
|
|
|
*want_length_out = 2u+usernamelen;
|
2010-08-03 23:28:55 +02:00
|
|
|
return 0;
|
2010-10-17 15:14:51 +02:00
|
|
|
}
|
2010-08-03 23:28:55 +02:00
|
|
|
req->replylen = 2; /* 2 bytes of response */
|
|
|
|
req->reply[0] = 5;
|
|
|
|
req->reply[1] = 0; /* authentication successful */
|
|
|
|
log_debug(LD_APP,
|
|
|
|
"socks5: Accepted username/password without checking.");
|
2010-10-17 15:14:51 +02:00
|
|
|
*drain_out = 2u + usernamelen + 1u + passlen;
|
2010-08-03 23:28:55 +02:00
|
|
|
return 0;
|
|
|
|
|
2003-10-04 03:37:01 +02:00
|
|
|
case 5: /* socks5 */
|
|
|
|
|
2004-11-28 10:05:49 +01:00
|
|
|
if (req->socks_version != 5) { /* we need to negotiate a method */
|
2009-07-31 23:03:35 +02:00
|
|
|
unsigned char nummethods = (unsigned char)*(data+1);
|
2010-08-03 23:28:55 +02:00
|
|
|
int r=0;
|
2004-04-25 22:37:37 +02:00
|
|
|
tor_assert(!req->socks_version);
|
2009-07-31 23:03:35 +02:00
|
|
|
if (datalen < 2u+nummethods) {
|
|
|
|
*want_length_out = 2u+nummethods;
|
2003-10-04 03:37:01 +02:00
|
|
|
return 0;
|
2009-07-31 23:03:35 +02:00
|
|
|
}
|
2010-08-03 23:28:55 +02:00
|
|
|
if (!nummethods)
|
|
|
|
return -1;
|
|
|
|
req->replylen = 2; /* 2 bytes of response */
|
|
|
|
req->reply[0] = 5; /* socks5 reply */
|
2010-10-17 15:14:51 +02:00
|
|
|
if (memchr(data+2, SOCKS_NO_AUTH, nummethods)) {
|
2010-08-03 23:28:55 +02:00
|
|
|
req->reply[1] = SOCKS_NO_AUTH; /* tell client to use "none" auth
|
|
|
|
method */
|
|
|
|
req->socks_version = 5; /* remember we've already negotiated auth */
|
|
|
|
log_debug(LD_APP,"socks5: accepted method 0 (no authentication)");
|
|
|
|
r=0;
|
2010-10-17 15:14:51 +02:00
|
|
|
}else if (memchr(data+2, SOCKS_USER_PASS,nummethods)) {
|
2010-08-03 23:28:55 +02:00
|
|
|
req->reply[1] = SOCKS_USER_PASS; /* tell client to use "user/pass"
|
|
|
|
auth method */
|
|
|
|
req->socks_version = 5; /* remember we've already negotiated auth */
|
|
|
|
log_debug(LD_APP,"socks5: accepted method 2 (username/password)");
|
|
|
|
r=0;
|
|
|
|
} else {
|
2006-02-13 09:28:42 +01:00
|
|
|
log_warn(LD_APP,
|
2010-08-03 23:28:55 +02:00
|
|
|
"socks5: offered methods don't include 'no auth' or "
|
|
|
|
"username/password. Rejecting.");
|
2004-03-09 23:01:17 +01:00
|
|
|
req->reply[1] = '\xFF'; /* reject all methods */
|
2010-08-03 23:28:55 +02:00
|
|
|
r=-1;
|
2003-11-16 18:00:02 +01:00
|
|
|
}
|
2006-08-24 06:51:55 +02:00
|
|
|
/* remove packet from buf. also remove any other extraneous
|
|
|
|
* bytes, to support broken socks clients. */
|
2009-07-31 23:03:35 +02:00
|
|
|
*drain_out = -1;
|
2003-10-04 03:37:01 +02:00
|
|
|
|
2010-08-03 23:28:55 +02:00
|
|
|
return r;
|
2003-10-04 03:37:01 +02:00
|
|
|
}
|
|
|
|
/* we know the method; read in the request */
|
2006-02-13 09:28:42 +01:00
|
|
|
log_debug(LD_APP,"socks5: checking request");
|
2009-07-31 23:03:35 +02:00
|
|
|
if (datalen < 8) {/* basic info plus >=2 for addr plus 2 for port */
|
|
|
|
*want_length_out = 8;
|
2003-10-04 03:37:01 +02:00
|
|
|
return 0; /* not yet */
|
2009-07-31 23:03:35 +02:00
|
|
|
}
|
|
|
|
req->command = (unsigned char) *(data+1);
|
2004-11-28 10:05:49 +01:00
|
|
|
if (req->command != SOCKS_COMMAND_CONNECT &&
|
2006-09-22 02:43:55 +02:00
|
|
|
req->command != SOCKS_COMMAND_RESOLVE &&
|
|
|
|
req->command != SOCKS_COMMAND_RESOLVE_PTR) {
|
|
|
|
/* not a connect or resolve or a resolve_ptr? we don't support it. */
|
2006-02-13 09:28:42 +01:00
|
|
|
log_warn(LD_APP,"socks5: command %d not recognized. Rejecting.",
|
|
|
|
req->command);
|
2003-10-04 03:37:01 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2009-07-31 23:03:35 +02:00
|
|
|
switch (*(data+3)) { /* address type */
|
2003-10-04 03:37:01 +02:00
|
|
|
case 1: /* IPv4 address */
|
2008-08-08 18:41:59 +02:00
|
|
|
case 4: /* IPv6 address */ {
|
2009-07-31 23:03:35 +02:00
|
|
|
const int is_v6 = *(data+3) == 4;
|
2008-08-08 18:41:59 +02:00
|
|
|
const unsigned addrlen = is_v6 ? 16 : 4;
|
2006-02-13 09:28:42 +01:00
|
|
|
log_debug(LD_APP,"socks5: ipv4 address type");
|
2009-07-31 23:03:35 +02:00
|
|
|
if (datalen < 6+addrlen) {/* ip/port there? */
|
|
|
|
*want_length_out = 6+addrlen;
|
2003-10-04 03:37:01 +02:00
|
|
|
return 0; /* not yet */
|
2009-07-31 23:03:35 +02:00
|
|
|
}
|
2004-08-07 06:03:01 +02:00
|
|
|
|
2008-08-08 18:41:59 +02:00
|
|
|
if (is_v6)
|
2009-07-31 23:03:35 +02:00
|
|
|
tor_addr_from_ipv6_bytes(&destaddr, data+4);
|
2008-08-08 18:41:59 +02:00
|
|
|
else
|
2009-07-31 23:03:35 +02:00
|
|
|
tor_addr_from_ipv4n(&destaddr, get_uint32(data+4));
|
2008-08-08 18:41:59 +02:00
|
|
|
|
|
|
|
tor_addr_to_str(tmpbuf, &destaddr, sizeof(tmpbuf), 1);
|
|
|
|
|
2004-11-28 10:05:49 +01:00
|
|
|
if (strlen(tmpbuf)+1 > MAX_SOCKS_ADDR_LEN) {
|
2006-02-13 09:28:42 +01:00
|
|
|
log_warn(LD_APP,
|
|
|
|
"socks5 IP takes %d bytes, which doesn't fit in %d. "
|
|
|
|
"Rejecting.",
|
|
|
|
(int)strlen(tmpbuf)+1,(int)MAX_SOCKS_ADDR_LEN);
|
2003-10-04 03:37:01 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2004-10-27 08:48:16 +02:00
|
|
|
strlcpy(req->address,tmpbuf,sizeof(req->address));
|
2009-07-31 23:03:35 +02:00
|
|
|
req->port = ntohs(get_uint16(data+4+addrlen));
|
|
|
|
*drain_out = 6+addrlen;
|
2006-09-22 02:43:55 +02:00
|
|
|
if (req->command != SOCKS_COMMAND_RESOLVE_PTR &&
|
2010-10-04 13:31:58 +02:00
|
|
|
!addressmap_have_mapping(req->address,0)) {
|
2010-11-15 21:41:21 +01:00
|
|
|
log_unsafe_socks_warning(5, req->address, req->port, safe_socks);
|
2006-03-19 02:44:53 +01:00
|
|
|
if (safe_socks)
|
|
|
|
return -1;
|
2004-08-07 06:03:01 +02:00
|
|
|
}
|
2003-10-04 03:37:01 +02:00
|
|
|
return 1;
|
2008-08-08 18:41:59 +02:00
|
|
|
}
|
2003-10-04 03:37:01 +02:00
|
|
|
case 3: /* fqdn */
|
2006-02-13 09:28:42 +01:00
|
|
|
log_debug(LD_APP,"socks5: fqdn address type");
|
2007-05-15 23:17:48 +02:00
|
|
|
if (req->command == SOCKS_COMMAND_RESOLVE_PTR) {
|
|
|
|
log_warn(LD_APP, "socks5 received RESOLVE_PTR command with "
|
|
|
|
"hostname type. Rejecting.");
|
|
|
|
return -1;
|
|
|
|
}
|
2009-07-31 23:03:35 +02:00
|
|
|
len = (unsigned char)*(data+4);
|
|
|
|
if (datalen < 7+len) { /* addr/port there? */
|
|
|
|
*want_length_out = 7+len;
|
2003-10-04 03:37:01 +02:00
|
|
|
return 0; /* not yet */
|
2009-07-31 23:03:35 +02:00
|
|
|
}
|
2004-11-28 10:05:49 +01:00
|
|
|
if (len+1 > MAX_SOCKS_ADDR_LEN) {
|
2006-02-13 09:28:42 +01:00
|
|
|
log_warn(LD_APP,
|
|
|
|
"socks5 hostname is %d bytes, which doesn't fit in "
|
|
|
|
"%d. Rejecting.", len+1,MAX_SOCKS_ADDR_LEN);
|
2003-10-04 03:37:01 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2009-07-31 23:03:35 +02:00
|
|
|
memcpy(req->address,data+5,len);
|
2003-11-16 18:00:02 +01:00
|
|
|
req->address[len] = 0;
|
2009-07-31 23:03:35 +02:00
|
|
|
req->port = ntohs(get_uint16(data+5+len));
|
|
|
|
*drain_out = 5+len+2;
|
2006-03-16 00:36:57 +01:00
|
|
|
if (!tor_strisprint(req->address) || strchr(req->address,'\"')) {
|
|
|
|
log_warn(LD_PROTOCOL,
|
2007-10-10 17:44:34 +02:00
|
|
|
"Your application (using socks5 to port %d) gave Tor "
|
2006-03-16 00:36:57 +01:00
|
|
|
"a malformed hostname: %s. Rejecting the connection.",
|
|
|
|
req->port, escaped(req->address));
|
|
|
|
return -1;
|
|
|
|
}
|
2005-11-17 00:37:35 +01:00
|
|
|
if (log_sockstype)
|
2006-02-13 09:28:42 +01:00
|
|
|
log_notice(LD_APP,
|
2007-10-10 17:44:34 +02:00
|
|
|
"Your application (using socks5 to port %d) gave "
|
2006-02-13 09:28:42 +01:00
|
|
|
"Tor a hostname, which means Tor will do the DNS resolve "
|
|
|
|
"for you. This is good.", req->port);
|
2003-10-04 03:37:01 +02:00
|
|
|
return 1;
|
|
|
|
default: /* unsupported */
|
2006-02-13 09:28:42 +01:00
|
|
|
log_warn(LD_APP,"socks5: unsupported address type %d. Rejecting.",
|
2009-07-31 23:03:35 +02:00
|
|
|
(int) *(data+3));
|
2003-10-04 03:37:01 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2004-04-25 22:37:37 +02:00
|
|
|
tor_assert(0);
|
2003-10-04 03:37:01 +02:00
|
|
|
case 4: /* socks4 */
|
2010-08-03 23:28:55 +02:00
|
|
|
/* http://ss5.sourceforge.net/socks4.protocol.txt */
|
|
|
|
/* http://ss5.sourceforge.net/socks4A.protocol.txt */
|
2003-10-04 03:37:01 +02:00
|
|
|
|
2003-11-11 03:41:31 +01:00
|
|
|
req->socks_version = 4;
|
2009-07-31 23:03:35 +02:00
|
|
|
if (datalen < SOCKS4_NETWORK_LEN) {/* basic info available? */
|
|
|
|
*want_length_out = SOCKS4_NETWORK_LEN;
|
2003-10-04 03:37:01 +02:00
|
|
|
return 0; /* not yet */
|
2009-07-31 23:03:35 +02:00
|
|
|
}
|
|
|
|
// buf_pullup(buf, 1280, 0);
|
|
|
|
req->command = (unsigned char) *(data+1);
|
2004-11-28 10:05:49 +01:00
|
|
|
if (req->command != SOCKS_COMMAND_CONNECT &&
|
2004-11-28 12:39:53 +01:00
|
|
|
req->command != SOCKS_COMMAND_RESOLVE) {
|
2006-09-22 02:43:55 +02:00
|
|
|
/* not a connect or resolve? we don't support it. (No resolve_ptr with
|
|
|
|
* socks4.) */
|
2006-02-13 09:28:42 +01:00
|
|
|
log_warn(LD_APP,"socks4: command %d not recognized. Rejecting.",
|
|
|
|
req->command);
|
2003-10-04 03:37:01 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-07-31 23:03:35 +02:00
|
|
|
req->port = ntohs(get_uint16(data+2));
|
|
|
|
destip = ntohl(get_uint32(data+4));
|
2004-11-28 10:05:49 +01:00
|
|
|
if ((!req->port && req->command!=SOCKS_COMMAND_RESOLVE) || !destip) {
|
2006-02-13 09:28:42 +01:00
|
|
|
log_warn(LD_APP,"socks4: Port or DestIP is zero. Rejecting.");
|
2003-10-04 03:37:01 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2004-11-28 10:05:49 +01:00
|
|
|
if (destip >> 8) {
|
2006-02-13 09:28:42 +01:00
|
|
|
log_debug(LD_APP,"socks4: destip not in form 0.0.0.x.");
|
2003-10-04 03:37:01 +02:00
|
|
|
in.s_addr = htonl(destip);
|
2005-02-22 09:18:36 +01:00
|
|
|
tor_inet_ntoa(&in,tmpbuf,sizeof(tmpbuf));
|
2004-11-28 10:05:49 +01:00
|
|
|
if (strlen(tmpbuf)+1 > MAX_SOCKS_ADDR_LEN) {
|
2006-02-13 09:28:42 +01:00
|
|
|
log_debug(LD_APP,"socks4 addr (%d bytes) too long. Rejecting.",
|
|
|
|
(int)strlen(tmpbuf));
|
2003-10-04 03:37:01 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2006-02-13 09:28:42 +01:00
|
|
|
log_debug(LD_APP,
|
2009-09-28 15:08:32 +02:00
|
|
|
"socks4: successfully read destip (%s)",
|
2009-12-15 23:23:36 +01:00
|
|
|
safe_str_client(tmpbuf));
|
2003-10-04 03:37:01 +02:00
|
|
|
socks4_prot = socks4;
|
|
|
|
}
|
|
|
|
|
2009-07-31 23:03:35 +02:00
|
|
|
next = memchr(data+SOCKS4_NETWORK_LEN, 0,
|
|
|
|
datalen-SOCKS4_NETWORK_LEN);
|
2004-11-28 10:05:49 +01:00
|
|
|
if (!next) {
|
2009-07-31 23:03:35 +02:00
|
|
|
if (datalen >= 1024) {
|
2007-12-26 01:12:08 +01:00
|
|
|
log_debug(LD_APP, "Socks4 user name too long; rejecting.");
|
|
|
|
return -1;
|
|
|
|
}
|
2006-02-13 09:28:42 +01:00
|
|
|
log_debug(LD_APP,"socks4: Username not here yet.");
|
2009-07-31 23:03:35 +02:00
|
|
|
*want_length_out = datalen+1024; /* ???? */
|
2003-10-04 03:37:01 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2009-07-31 23:03:35 +02:00
|
|
|
tor_assert(next < data+datalen);
|
2003-10-04 03:37:01 +02:00
|
|
|
|
2004-11-10 15:26:34 +01:00
|
|
|
startaddr = NULL;
|
2005-09-24 23:56:04 +02:00
|
|
|
if (socks4_prot != socks4a &&
|
2010-10-04 13:31:58 +02:00
|
|
|
!addressmap_have_mapping(tmpbuf,0)) {
|
2010-11-15 21:41:21 +01:00
|
|
|
log_unsafe_socks_warning(4, tmpbuf, req->port, safe_socks);
|
2010-10-04 13:31:58 +02:00
|
|
|
|
2006-03-19 02:44:53 +01:00
|
|
|
if (safe_socks)
|
|
|
|
return -1;
|
2004-08-04 01:42:33 +02:00
|
|
|
}
|
2004-12-22 11:04:50 +01:00
|
|
|
if (socks4_prot == socks4a) {
|
2009-07-31 23:03:35 +02:00
|
|
|
if (next+1 == data+datalen) {
|
2006-02-13 09:28:42 +01:00
|
|
|
log_debug(LD_APP,"socks4: No part of destaddr here yet.");
|
2010-04-10 00:45:08 +02:00
|
|
|
*want_length_out = datalen + 1024; /* More than we need, but safe */
|
2004-12-22 11:04:50 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2004-11-10 15:26:34 +01:00
|
|
|
startaddr = next+1;
|
2009-07-31 23:03:35 +02:00
|
|
|
next = memchr(startaddr, 0, data + datalen - startaddr);
|
2004-11-28 10:05:49 +01:00
|
|
|
if (!next) {
|
2009-07-31 23:03:35 +02:00
|
|
|
if (datalen >= 1024) {
|
2007-12-26 01:12:08 +01:00
|
|
|
log_debug(LD_APP,"socks4: Destaddr too long.");
|
|
|
|
return -1;
|
|
|
|
}
|
2006-02-13 09:28:42 +01:00
|
|
|
log_debug(LD_APP,"socks4: Destaddr not all here yet.");
|
2009-07-31 23:03:35 +02:00
|
|
|
*want_length_out = datalen + 1024;
|
2003-10-04 03:37:01 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2004-11-28 10:05:49 +01:00
|
|
|
if (MAX_SOCKS_ADDR_LEN <= next-startaddr) {
|
2006-02-13 09:28:42 +01:00
|
|
|
log_warn(LD_APP,"socks4: Destaddr too long. Rejecting.");
|
2003-10-04 03:37:01 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2007-12-26 01:12:08 +01:00
|
|
|
// tor_assert(next < buf->cur+buf->datalen);
|
2006-03-05 10:50:26 +01:00
|
|
|
|
2005-11-17 00:37:35 +01:00
|
|
|
if (log_sockstype)
|
2006-02-13 09:28:42 +01:00
|
|
|
log_notice(LD_APP,
|
2007-10-10 17:44:34 +02:00
|
|
|
"Your application (using socks4a to port %d) gave "
|
2006-02-13 09:28:42 +01:00
|
|
|
"Tor a hostname, which means Tor will do the DNS resolve "
|
|
|
|
"for you. This is good.", req->port);
|
2003-10-04 03:37:01 +02:00
|
|
|
}
|
2006-02-13 09:28:42 +01:00
|
|
|
log_debug(LD_APP,"socks4: Everything is here. Success.");
|
2004-11-10 15:26:34 +01:00
|
|
|
strlcpy(req->address, startaddr ? startaddr : tmpbuf,
|
2004-10-27 08:48:16 +02:00
|
|
|
sizeof(req->address));
|
2006-03-16 00:36:57 +01:00
|
|
|
if (!tor_strisprint(req->address) || strchr(req->address,'\"')) {
|
|
|
|
log_warn(LD_PROTOCOL,
|
2007-10-10 17:44:34 +02:00
|
|
|
"Your application (using socks4 to port %d) gave Tor "
|
2006-03-16 00:36:57 +01:00
|
|
|
"a malformed hostname: %s. Rejecting the connection.",
|
|
|
|
req->port, escaped(req->address));
|
|
|
|
return -1;
|
|
|
|
}
|
2005-12-14 21:40:40 +01:00
|
|
|
/* next points to the final \0 on inbuf */
|
2009-07-31 23:03:35 +02:00
|
|
|
*drain_out = next - data + 1;
|
2003-10-04 03:37:01 +02:00
|
|
|
return 1;
|
|
|
|
|
2004-02-26 23:02:22 +01:00
|
|
|
case 'G': /* get */
|
|
|
|
case 'H': /* head */
|
|
|
|
case 'P': /* put/post */
|
|
|
|
case 'C': /* connect */
|
2004-10-27 08:48:16 +02:00
|
|
|
strlcpy(req->reply,
|
2004-02-26 23:02:22 +01:00
|
|
|
"HTTP/1.0 501 Tor is not an HTTP Proxy\r\n"
|
2004-02-26 23:10:55 +01:00
|
|
|
"Content-Type: text/html; charset=iso-8859-1\r\n\r\n"
|
2004-02-26 23:02:22 +01:00
|
|
|
"<html>\n"
|
|
|
|
"<head>\n"
|
|
|
|
"<title>Tor is not an HTTP Proxy</title>\n"
|
|
|
|
"</head>\n"
|
|
|
|
"<body>\n"
|
2004-02-27 02:33:02 +01:00
|
|
|
"<h1>Tor is not an HTTP Proxy</h1>\n"
|
|
|
|
"<p>\n"
|
2005-12-14 21:40:40 +01:00
|
|
|
"It appears you have configured your web browser to use Tor as an HTTP proxy."
|
|
|
|
"\n"
|
|
|
|
"This is not correct: Tor is a SOCKS proxy, not an HTTP proxy.\n"
|
|
|
|
"Please configure your client accordingly.\n"
|
2004-02-27 02:33:02 +01:00
|
|
|
"</p>\n"
|
|
|
|
"<p>\n"
|
2007-12-07 00:56:36 +01:00
|
|
|
"See <a href=\"https://www.torproject.org/documentation.html\">"
|
2007-12-07 22:27:58 +01:00
|
|
|
"https://www.torproject.org/documentation.html</a> for more "
|
|
|
|
"information.\n"
|
2005-12-09 06:37:26 +01:00
|
|
|
"<!-- Plus this comment, to make the body response more than 512 bytes, so "
|
|
|
|
" IE will be willing to display it. Comment comment comment comment "
|
|
|
|
" comment comment comment comment comment comment comment comment.-->\n"
|
2004-02-27 02:33:02 +01:00
|
|
|
"</p>\n"
|
2004-02-26 23:02:22 +01:00
|
|
|
"</body>\n"
|
|
|
|
"</html>\n"
|
2004-10-27 08:48:16 +02:00
|
|
|
, MAX_SOCKS_REPLY_LEN);
|
2004-02-26 23:02:22 +01:00
|
|
|
req->replylen = strlen(req->reply)+1;
|
|
|
|
/* fall through */
|
2003-10-04 03:37:01 +02:00
|
|
|
default: /* version is not socks4 or socks5 */
|
2006-02-13 09:28:42 +01:00
|
|
|
log_warn(LD_APP,
|
|
|
|
"Socks version %d not recognized. (Tor is not an http proxy.)",
|
2009-07-31 23:03:35 +02:00
|
|
|
*(data));
|
2007-01-06 06:42:31 +01:00
|
|
|
{
|
2010-04-10 00:45:08 +02:00
|
|
|
/* Tell the controller the first 8 bytes. */
|
|
|
|
char *tmp = tor_strndup(data, datalen < 8 ? datalen : 8);
|
2007-01-06 06:42:31 +01:00
|
|
|
control_event_client_status(LOG_WARN,
|
|
|
|
"SOCKS_UNKNOWN_PROTOCOL DATA=\"%s\"",
|
|
|
|
escaped(tmp));
|
|
|
|
tor_free(tmp);
|
|
|
|
}
|
2003-09-18 10:11:31 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-19 01:59:18 +02:00
|
|
|
/** Inspect a reply from SOCKS server stored in <b>buf</b> according
|
|
|
|
* to <b>state</b>, removing the protocol data upon success. Return 0 on
|
|
|
|
* incomplete response, 1 on success and -1 on error, in which case
|
|
|
|
* <b>reason</b> is set to a descriptive message (free() when finished
|
|
|
|
* with it).
|
|
|
|
*
|
|
|
|
* As a special case, 2 is returned when user/pass is required
|
|
|
|
* during SOCKS5 handshake and user/pass is configured.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
fetch_from_buf_socks_client(buf_t *buf, int state, char **reason)
|
|
|
|
{
|
2009-08-26 17:55:36 +02:00
|
|
|
ssize_t drain = 0;
|
|
|
|
int r;
|
2009-06-19 01:59:18 +02:00
|
|
|
if (buf->datalen < 2)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
buf_pullup(buf, 128, 0);
|
|
|
|
tor_assert(buf->head && buf->head->datalen >= 2);
|
|
|
|
|
2009-08-26 17:55:36 +02:00
|
|
|
r = parse_socks_client((uint8_t*)buf->head->data, buf->head->datalen,
|
|
|
|
state, reason, &drain);
|
|
|
|
if (drain > 0)
|
|
|
|
buf_remove_from_front(buf, drain);
|
|
|
|
else if (drain < 0)
|
|
|
|
buf_clear(buf);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef USE_BUFFEREVENTS
|
|
|
|
/** As fetch_from_buf_socks_client, buf works on an evbuffer */
|
|
|
|
int
|
|
|
|
fetch_from_evbuffer_socks_client(struct evbuffer *buf, int state,
|
|
|
|
char **reason)
|
|
|
|
{
|
|
|
|
ssize_t drain = 0;
|
|
|
|
uint8_t *data;
|
2010-04-10 00:45:08 +02:00
|
|
|
size_t datalen;
|
2009-08-26 17:55:36 +02:00
|
|
|
int r;
|
|
|
|
|
2010-04-10 00:45:08 +02:00
|
|
|
data = evbuffer_pullup(buf, 128); /* Make sure we have at least 128
|
|
|
|
* contiguous bytes if possible. */
|
|
|
|
datalen = evbuffer_get_contiguous_space(buf);
|
2009-08-26 17:55:36 +02:00
|
|
|
r = parse_socks_client(data, datalen, state, reason, &drain);
|
|
|
|
if (drain > 0)
|
|
|
|
evbuffer_drain(buf, drain);
|
|
|
|
else
|
|
|
|
evbuffer_drain(buf, evbuffer_get_length(buf));
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/** Implementation logic for fetch_from_*_socks_client. */
|
|
|
|
static int
|
|
|
|
parse_socks_client(const uint8_t *data, size_t datalen,
|
|
|
|
int state, char **reason,
|
|
|
|
ssize_t *drain_out)
|
|
|
|
{
|
|
|
|
unsigned int addrlen;
|
|
|
|
*drain_out = 0;
|
|
|
|
if (datalen < 2)
|
|
|
|
return 0;
|
2009-06-19 01:59:18 +02:00
|
|
|
|
|
|
|
switch (state) {
|
|
|
|
case PROXY_SOCKS4_WANT_CONNECT_OK:
|
|
|
|
/* Wait for the complete response */
|
2009-08-26 17:55:36 +02:00
|
|
|
if (datalen < 8)
|
2009-06-19 01:59:18 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (data[1] != 0x5a) {
|
2009-06-19 18:40:23 +02:00
|
|
|
*reason = tor_strdup(socks4_response_code_to_string(data[1]));
|
2009-06-19 01:59:18 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Success */
|
2009-08-26 17:55:36 +02:00
|
|
|
*drain_out = 8;
|
2009-06-19 01:59:18 +02:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
case PROXY_SOCKS5_WANT_AUTH_METHOD_NONE:
|
|
|
|
/* we don't have any credentials */
|
|
|
|
if (data[1] != 0x00) {
|
|
|
|
*reason = tor_strdup("server doesn't support any of our "
|
|
|
|
"available authentication methods");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
log_info(LD_NET, "SOCKS 5 client: continuing without authentication");
|
2009-08-26 17:55:36 +02:00
|
|
|
*drain_out = -1;
|
2009-06-19 01:59:18 +02:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
case PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929:
|
|
|
|
/* we have a username and password. return 1 if we can proceed without
|
|
|
|
* providing authentication, or 2 otherwise. */
|
|
|
|
switch (data[1]) {
|
|
|
|
case 0x00:
|
|
|
|
log_info(LD_NET, "SOCKS 5 client: we have auth details but server "
|
|
|
|
"doesn't require authentication.");
|
2009-08-26 17:55:36 +02:00
|
|
|
*drain_out = -1;
|
2009-06-19 01:59:18 +02:00
|
|
|
return 1;
|
|
|
|
case 0x02:
|
|
|
|
log_info(LD_NET, "SOCKS 5 client: need authentication.");
|
2009-08-26 17:55:36 +02:00
|
|
|
*drain_out = -1;
|
2009-06-19 01:59:18 +02:00
|
|
|
return 2;
|
|
|
|
/* fall through */
|
|
|
|
}
|
|
|
|
|
|
|
|
*reason = tor_strdup("server doesn't support any of our available "
|
|
|
|
"authentication methods");
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
case PROXY_SOCKS5_WANT_AUTH_RFC1929_OK:
|
|
|
|
/* handle server reply to rfc1929 authentication */
|
|
|
|
if (data[1] != 0x00) {
|
|
|
|
*reason = tor_strdup("authentication failed");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
log_info(LD_NET, "SOCKS 5 client: authentication successful.");
|
2009-08-26 17:55:36 +02:00
|
|
|
*drain_out = -1;
|
2009-06-19 01:59:18 +02:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
case PROXY_SOCKS5_WANT_CONNECT_OK:
|
|
|
|
/* response is variable length. BND.ADDR, etc, isn't needed
|
|
|
|
* (don't bother with buf_pullup()), but make sure to eat all
|
|
|
|
* the data used */
|
|
|
|
|
|
|
|
/* wait for address type field to arrive */
|
2009-08-26 17:55:36 +02:00
|
|
|
if (datalen < 4)
|
2009-06-19 01:59:18 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
switch (data[3]) {
|
|
|
|
case 0x01: /* ip4 */
|
|
|
|
addrlen = 4;
|
|
|
|
break;
|
|
|
|
case 0x04: /* ip6 */
|
|
|
|
addrlen = 16;
|
|
|
|
break;
|
|
|
|
case 0x03: /* fqdn (can this happen here?) */
|
2009-08-26 17:55:36 +02:00
|
|
|
if (datalen < 5)
|
2009-06-19 01:59:18 +02:00
|
|
|
return 0;
|
|
|
|
addrlen = 1 + data[4];
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
*reason = tor_strdup("invalid response to connect request");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* wait for address and port */
|
2009-08-26 17:55:36 +02:00
|
|
|
if (datalen < 6 + addrlen)
|
2009-06-19 01:59:18 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (data[1] != 0x00) {
|
2009-06-19 18:40:23 +02:00
|
|
|
*reason = tor_strdup(socks5_response_code_to_string(data[1]));
|
2009-06-19 01:59:18 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-08-26 17:55:36 +02:00
|
|
|
*drain_out = 6 + addrlen;
|
2009-06-19 01:59:18 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* shouldn't get here... */
|
|
|
|
tor_assert(0);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-03-04 22:08:28 +01:00
|
|
|
/** Return 1 iff buf looks more like it has an (obsolete) v0 controller
|
|
|
|
* command on it than any valid v1 controller command. */
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
2007-03-04 22:08:28 +01:00
|
|
|
peek_buf_has_control0_command(buf_t *buf)
|
2004-11-03 02:32:26 +01:00
|
|
|
{
|
2007-03-04 22:08:28 +01:00
|
|
|
if (buf->datalen >= 4) {
|
|
|
|
char header[4];
|
|
|
|
uint16_t cmd;
|
|
|
|
peek_from_buf(header, sizeof(header), buf);
|
|
|
|
cmd = ntohs(get_uint16(header+2));
|
|
|
|
if (cmd <= 0x14)
|
|
|
|
return 1; /* This is definitely not a v1 control command. */
|
2005-03-02 21:22:10 +01:00
|
|
|
}
|
2007-03-04 22:08:28 +01:00
|
|
|
return 0;
|
2004-11-03 02:32:26 +01:00
|
|
|
}
|
|
|
|
|
2009-08-09 20:40:28 +02:00
|
|
|
#ifdef USE_BUFFEREVENTS
|
|
|
|
int
|
|
|
|
peek_evbuffer_has_control0_command(struct evbuffer *buf)
|
|
|
|
{
|
|
|
|
int result = 0;
|
|
|
|
if (evbuffer_get_length(buf) >= 4) {
|
|
|
|
int free_out = 0;
|
|
|
|
char *data = NULL;
|
2009-08-11 22:56:09 +02:00
|
|
|
size_t n = inspect_evbuffer(buf, &data, 4, &free_out, NULL);
|
2009-08-09 20:40:28 +02:00
|
|
|
uint16_t cmd;
|
|
|
|
tor_assert(n >= 4);
|
|
|
|
cmd = ntohs(get_uint16(data+2));
|
|
|
|
if (cmd <= 0x14)
|
|
|
|
result = 1;
|
|
|
|
if (free_out)
|
|
|
|
tor_free(data);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-02-06 17:58:05 +01:00
|
|
|
/** Return the index within <b>buf</b> at which <b>ch</b> first appears,
|
|
|
|
* or -1 if <b>ch</b> does not appear on buf. */
|
2008-02-22 04:44:36 +01:00
|
|
|
static off_t
|
2007-12-29 03:33:42 +01:00
|
|
|
buf_find_offset_of_char(buf_t *buf, char ch)
|
|
|
|
{
|
|
|
|
chunk_t *chunk;
|
2008-02-22 04:44:36 +01:00
|
|
|
off_t offset = 0;
|
2007-12-29 03:33:42 +01:00
|
|
|
for (chunk = buf->head; chunk; chunk = chunk->next) {
|
|
|
|
char *cp = memchr(chunk->data, ch, chunk->datalen);
|
|
|
|
if (cp)
|
|
|
|
return offset + (cp - chunk->data);
|
|
|
|
else
|
|
|
|
offset += chunk->datalen;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-07-31 19:44:43 +02:00
|
|
|
/** Try to read a single LF-terminated line from <b>buf</b>, and write it
|
|
|
|
* (including the LF), NUL-terminated, into the *<b>data_len</b> byte buffer
|
|
|
|
* at <b>data_out</b>. Set *<b>data_len</b> to the number of bytes in the
|
|
|
|
* line, not counting the terminating NUL. Return 1 if we read a whole line,
|
|
|
|
* return 0 if we don't have a whole line yet, and return -1 if the line
|
|
|
|
* length exceeds *<b>data_len</b>.
|
2006-11-14 01:06:31 +01:00
|
|
|
*/
|
|
|
|
int
|
2007-08-29 21:02:33 +02:00
|
|
|
fetch_from_buf_line(buf_t *buf, char *data_out, size_t *data_len)
|
2006-11-14 01:06:31 +01:00
|
|
|
{
|
|
|
|
size_t sz;
|
2008-02-22 04:44:36 +01:00
|
|
|
off_t offset;
|
2006-11-14 01:06:31 +01:00
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
if (!buf->head)
|
|
|
|
return 0;
|
2007-12-29 03:33:42 +01:00
|
|
|
|
|
|
|
offset = buf_find_offset_of_char(buf, '\n');
|
|
|
|
if (offset < 0)
|
2006-11-14 01:06:31 +01:00
|
|
|
return 0;
|
2007-12-29 03:33:42 +01:00
|
|
|
sz = (size_t) offset;
|
2006-11-14 01:06:31 +01:00
|
|
|
if (sz+2 > *data_len) {
|
2007-12-29 03:33:42 +01:00
|
|
|
*data_len = sz + 2;
|
2006-11-14 01:06:31 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
fetch_from_buf(data_out, sz+1, buf);
|
|
|
|
data_out[sz+1] = '\0';
|
|
|
|
*data_len = sz+1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2006-08-28 05:16:02 +02:00
|
|
|
/** Compress on uncompress the <b>data_len</b> bytes in <b>data</b> using the
|
|
|
|
* zlib state <b>state</b>, appending the result to <b>buf</b>. If
|
|
|
|
* <b>done</b> is true, flush the data in the state and finish the
|
|
|
|
* compression/uncompression. Return -1 on failure, 0 on success. */
|
2006-06-18 09:27:47 +02:00
|
|
|
int
|
|
|
|
write_to_buf_zlib(buf_t *buf, tor_zlib_state_t *state,
|
|
|
|
const char *data, size_t data_len,
|
|
|
|
int done)
|
|
|
|
{
|
|
|
|
char *next;
|
|
|
|
size_t old_avail, avail;
|
2006-06-18 11:03:48 +02:00
|
|
|
int over = 0;
|
2006-06-24 04:10:21 +02:00
|
|
|
do {
|
2007-12-26 01:12:08 +01:00
|
|
|
int need_new_chunk = 0;
|
|
|
|
if (!buf->tail || ! CHUNK_REMAINING_CAPACITY(buf->tail)) {
|
|
|
|
size_t cap = data_len / 4;
|
2007-12-29 06:16:30 +01:00
|
|
|
buf_add_chunk_with_capacity(buf, cap, 1);
|
2007-12-26 01:12:08 +01:00
|
|
|
}
|
|
|
|
next = CHUNK_WRITE_PTR(buf->tail);
|
|
|
|
avail = old_avail = CHUNK_REMAINING_CAPACITY(buf->tail);
|
2006-06-18 09:27:47 +02:00
|
|
|
switch (tor_zlib_process(state, &next, &avail, &data, &data_len, done)) {
|
|
|
|
case TOR_ZLIB_DONE:
|
2006-06-18 11:03:48 +02:00
|
|
|
over = 1;
|
|
|
|
break;
|
2006-06-18 09:27:47 +02:00
|
|
|
case TOR_ZLIB_ERR:
|
|
|
|
return -1;
|
|
|
|
case TOR_ZLIB_OK:
|
|
|
|
if (data_len == 0)
|
2006-06-18 11:03:48 +02:00
|
|
|
over = 1;
|
2006-06-18 09:27:47 +02:00
|
|
|
break;
|
|
|
|
case TOR_ZLIB_BUF_FULL:
|
2007-12-26 01:12:08 +01:00
|
|
|
if (avail) {
|
|
|
|
/* Zlib says we need more room (ZLIB_BUF_FULL). Start a new chunk
|
|
|
|
* automatically, whether were going to or not. */
|
|
|
|
need_new_chunk = 1;
|
2006-06-18 09:27:47 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
buf->datalen += old_avail - avail;
|
2007-12-26 01:12:08 +01:00
|
|
|
buf->tail->datalen += old_avail - avail;
|
|
|
|
if (need_new_chunk) {
|
2007-12-29 06:16:30 +01:00
|
|
|
buf_add_chunk_with_capacity(buf, data_len/4, 1);
|
2007-12-26 01:12:08 +01:00
|
|
|
}
|
|
|
|
|
2006-06-24 04:10:21 +02:00
|
|
|
} while (!over);
|
2007-12-26 01:12:08 +01:00
|
|
|
check();
|
2006-06-18 22:39:46 +02:00
|
|
|
return 0;
|
2006-06-18 09:27:47 +02:00
|
|
|
}
|
|
|
|
|
2009-08-26 21:33:19 +02:00
|
|
|
#ifdef USE_BUFFEREVENTS
|
|
|
|
int
|
|
|
|
write_to_evbuffer_zlib(struct evbuffer *buf, tor_zlib_state_t *state,
|
|
|
|
const char *data, size_t data_len,
|
|
|
|
int done)
|
|
|
|
{
|
|
|
|
char *next;
|
|
|
|
size_t old_avail, avail;
|
|
|
|
int over = 0, n;
|
|
|
|
struct evbuffer_iovec vec[1];
|
|
|
|
do {
|
|
|
|
int need_new_chunk = 0;
|
|
|
|
{
|
|
|
|
size_t cap = data_len / 4;
|
|
|
|
if (cap < 128)
|
|
|
|
cap = 128;
|
|
|
|
/* XXXX NM this strategy is fragmentation-prone. We should really have
|
|
|
|
* two iovecs, and write first into the one, and then into the
|
|
|
|
* second if the first gets full. */
|
|
|
|
n = evbuffer_reserve_space(buf, cap, vec, 1);
|
|
|
|
tor_assert(n == 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
next = vec[0].iov_base;
|
|
|
|
avail = old_avail = vec[0].iov_len;
|
|
|
|
|
|
|
|
switch (tor_zlib_process(state, &next, &avail, &data, &data_len, done)) {
|
|
|
|
case TOR_ZLIB_DONE:
|
|
|
|
over = 1;
|
|
|
|
break;
|
|
|
|
case TOR_ZLIB_ERR:
|
|
|
|
return -1;
|
|
|
|
case TOR_ZLIB_OK:
|
|
|
|
if (data_len == 0)
|
|
|
|
over = 1;
|
|
|
|
break;
|
|
|
|
case TOR_ZLIB_BUF_FULL:
|
|
|
|
if (avail) {
|
|
|
|
/* Zlib says we need more room (ZLIB_BUF_FULL). Start a new chunk
|
|
|
|
* automatically, whether were going to or not. */
|
|
|
|
need_new_chunk = 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXXX possible infinite loop on BUF_FULL. */
|
|
|
|
vec[0].iov_len = old_avail - avail;
|
|
|
|
evbuffer_commit_space(buf, vec, 1);
|
|
|
|
|
|
|
|
} while (!over);
|
|
|
|
check();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/** Log an error and exit if <b>buf</b> is corrupted.
|
2004-05-02 00:08:43 +02:00
|
|
|
*/
|
2005-09-30 03:09:52 +02:00
|
|
|
void
|
|
|
|
assert_buf_ok(buf_t *buf)
|
2004-03-03 23:49:15 +01:00
|
|
|
{
|
2004-04-25 22:37:37 +02:00
|
|
|
tor_assert(buf);
|
|
|
|
tor_assert(buf->magic == BUFFER_MAGIC);
|
2007-04-23 16:42:27 +02:00
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
if (! buf->head) {
|
|
|
|
tor_assert(!buf->tail);
|
|
|
|
tor_assert(buf->datalen == 0);
|
2007-04-23 16:42:27 +02:00
|
|
|
} else {
|
2007-12-26 01:12:08 +01:00
|
|
|
chunk_t *ch;
|
|
|
|
size_t total = 0;
|
|
|
|
tor_assert(buf->tail);
|
|
|
|
for (ch = buf->head; ch; ch = ch->next) {
|
|
|
|
total += ch->datalen;
|
|
|
|
tor_assert(ch->datalen <= ch->memlen);
|
|
|
|
tor_assert(ch->data >= &ch->mem[0]);
|
|
|
|
tor_assert(ch->data < &ch->mem[0]+ch->memlen);
|
|
|
|
tor_assert(ch->data+ch->datalen <= &ch->mem[0] + ch->memlen);
|
|
|
|
if (!ch->next)
|
|
|
|
tor_assert(ch == buf->tail);
|
|
|
|
}
|
|
|
|
tor_assert(buf->datalen == total);
|
2007-04-23 16:42:27 +02:00
|
|
|
}
|
2007-12-26 01:12:08 +01:00
|
|
|
}
|
2007-04-23 16:42:27 +02:00
|
|
|
|
2008-01-13 01:20:44 +01:00
|
|
|
#ifdef ENABLE_BUF_FREELISTS
|
2007-12-26 01:12:08 +01:00
|
|
|
/** Log an error and exit if <b>fl</b> is corrupted.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
assert_freelist_ok(chunk_freelist_t *fl)
|
|
|
|
{
|
|
|
|
chunk_t *ch;
|
|
|
|
int n;
|
|
|
|
tor_assert(fl->alloc_size > 0);
|
|
|
|
n = 0;
|
|
|
|
for (ch = fl->head; ch; ch = ch->next) {
|
|
|
|
tor_assert(CHUNK_ALLOC_SIZE(ch->memlen) == fl->alloc_size);
|
|
|
|
++n;
|
2005-04-27 02:53:44 +02:00
|
|
|
}
|
2007-12-26 01:12:08 +01:00
|
|
|
tor_assert(n == fl->cur_length);
|
|
|
|
tor_assert(n >= fl->lowest_length);
|
|
|
|
tor_assert(n <= fl->max_length);
|
2004-03-03 23:49:15 +01:00
|
|
|
}
|
2008-01-13 01:20:44 +01:00
|
|
|
#endif
|
2005-06-09 21:03:31 +02:00
|
|
|
|