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.
|
2016-02-27 18:48:19 +01:00
|
|
|
* Copyright (c) 2007-2016, 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
|
2016-10-15 02:08:51 +02:00
|
|
|
* \brief Implements a generic buffer interface.
|
|
|
|
*
|
|
|
|
* A buf_t is a (fairly) opaque byte-oriented FIFO that can read to or flush
|
|
|
|
* from memory, sockets, file descriptors, TLS connections, or another buf_t.
|
|
|
|
* Buffers are implemented as linked lists of memory chunks.
|
|
|
|
*
|
|
|
|
* All socket-backed and TLS-based connection_t objects have a pair of
|
|
|
|
* buffers: one for incoming data, and one for outcoming data. These are fed
|
|
|
|
* and drained from functions in connection.c, trigged by events that are
|
|
|
|
* monitored in main.c.
|
|
|
|
*
|
|
|
|
* This module has basic support for reading and writing on buf_t objects. It
|
|
|
|
* also contains specialized functions for handling particular protocols
|
|
|
|
* on a buf_t backend, including SOCKS (used in connection_edge.c), Tor cells
|
|
|
|
* (used in connection_or.c and channeltls.c), HTTP (used in directory.c), and
|
|
|
|
* line-oriented communication (used in control.c).
|
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"
|
2012-10-28 21:13:58 +01:00
|
|
|
#include "addressmap.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"
|
2012-12-05 18:18:18 +01:00
|
|
|
#include "ext_orport.h"
|
2015-02-27 15:24:21 +01:00
|
|
|
#include "util.h"
|
|
|
|
#include "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
|
|
|
|
2014-09-29 15:17:20 +02:00
|
|
|
static void socks_request_set_socks5_error(socks_request_t *req,
|
2014-09-21 18:17:44 +02:00
|
|
|
socks5_reply_status_t reason);
|
|
|
|
|
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 */
|
|
|
|
|
2008-07-31 14:18:14 +02:00
|
|
|
#define CHUNK_HEADER_LEN STRUCT_OFFSET(chunk_t, mem[0])
|
|
|
|
|
2016-10-14 15:38:12 +02:00
|
|
|
/* We leave this many NUL bytes at the end of the buffer. */
|
|
|
|
#define SENTINEL_LEN 4
|
|
|
|
|
|
|
|
/* Header size plus NUL bytes at the end */
|
|
|
|
#define CHUNK_OVERHEAD (CHUNK_HEADER_LEN + SENTINEL_LEN)
|
|
|
|
|
2007-12-26 01:12:08 +01:00
|
|
|
/** Return the number of bytes needed to allocate a chunk to hold
|
|
|
|
* <b>memlen</b> bytes. */
|
2016-10-14 15:38:12 +02:00
|
|
|
#define CHUNK_ALLOC_SIZE(memlen) (CHUNK_OVERHEAD + (memlen))
|
2007-12-26 01:12:08 +01:00
|
|
|
/** Return the number of usable bytes in a chunk allocated with
|
|
|
|
* malloc(<b>memlen</b>). */
|
2016-10-14 15:38:12 +02:00
|
|
|
#define CHUNK_SIZE_WITH_ALLOC(memlen) ((memlen) - CHUNK_OVERHEAD)
|
|
|
|
|
|
|
|
#define DEBUG_SENTINEL
|
|
|
|
|
|
|
|
#ifdef DEBUG_SENTINEL
|
|
|
|
#define DBG_S(s) s
|
|
|
|
#else
|
|
|
|
#define DBG_S(s) (void)0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define CHUNK_SET_SENTINEL(chunk, alloclen) do { \
|
|
|
|
uint8_t *a = (uint8_t*) &(chunk)->mem[(chunk)->memlen]; \
|
|
|
|
DBG_S(uint8_t *b = &((uint8_t*)(chunk))[(alloclen)-SENTINEL_LEN]); \
|
|
|
|
DBG_S(tor_assert(a == b)); \
|
|
|
|
memset(a,0,SENTINEL_LEN); \
|
|
|
|
} while (0)
|
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. */
|
2015-12-10 16:19:43 +01: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. */
|
2015-12-10 16:19:43 +01:00
|
|
|
static inline size_t
|
2007-12-26 01:12:08 +01:00
|
|
|
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. */
|
2015-12-10 16:19:43 +01:00
|
|
|
static inline void
|
2007-12-26 01:12:08 +01:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2014-04-29 11:18:34 +02:00
|
|
|
/** Keep track of total size of allocated chunks for consistency asserts */
|
|
|
|
static size_t total_bytes_allocated_in_chunks = 0;
|
2008-01-13 01:20:44 +01:00
|
|
|
static void
|
2016-04-15 18:20:14 +02:00
|
|
|
buf_chunk_free_unchecked(chunk_t *chunk)
|
2008-01-13 01:20:44 +01:00
|
|
|
{
|
2013-11-16 00:38:52 +01:00
|
|
|
if (!chunk)
|
|
|
|
return;
|
2014-01-03 19:56:46 +01:00
|
|
|
#ifdef DEBUG_CHUNK_ALLOC
|
|
|
|
tor_assert(CHUNK_ALLOC_SIZE(chunk->memlen) == chunk->DBG_alloc);
|
|
|
|
#endif
|
2014-03-05 20:36:32 +01:00
|
|
|
tor_assert(total_bytes_allocated_in_chunks >=
|
|
|
|
CHUNK_ALLOC_SIZE(chunk->memlen));
|
2013-11-16 00:38:52 +01:00
|
|
|
total_bytes_allocated_in_chunks -= CHUNK_ALLOC_SIZE(chunk->memlen);
|
2008-01-13 01:20:44 +01:00
|
|
|
tor_free(chunk);
|
|
|
|
}
|
2015-12-10 16:19:43 +01:00
|
|
|
static inline chunk_t *
|
2008-01-13 01:20:44 +01:00
|
|
|
chunk_new_with_alloc_size(size_t alloc)
|
|
|
|
{
|
|
|
|
chunk_t *ch;
|
2012-08-13 19:27:32 +02:00
|
|
|
ch = tor_malloc(alloc);
|
2008-01-13 01:20:44 +01:00
|
|
|
ch->next = NULL;
|
|
|
|
ch->datalen = 0;
|
2014-01-03 19:56:46 +01:00
|
|
|
#ifdef DEBUG_CHUNK_ALLOC
|
|
|
|
ch->DBG_alloc = alloc;
|
|
|
|
#endif
|
2008-01-13 01:20:44 +01:00
|
|
|
ch->memlen = CHUNK_SIZE_WITH_ALLOC(alloc);
|
2013-11-16 00:38:52 +01:00
|
|
|
total_bytes_allocated_in_chunks += alloc;
|
2008-01-13 01:20:44 +01:00
|
|
|
ch->data = &ch->mem[0];
|
2016-10-14 15:38:12 +02:00
|
|
|
CHUNK_SET_SENTINEL(ch, alloc);
|
2008-01-13 01:20:44 +01:00
|
|
|
return ch;
|
|
|
|
}
|
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. */
|
2015-12-10 16:19:43 +01:00
|
|
|
static inline chunk_t *
|
2007-12-26 01:12:08 +01:00
|
|
|
chunk_grow(chunk_t *chunk, size_t sz)
|
|
|
|
{
|
|
|
|
off_t offset;
|
2016-10-14 15:38:12 +02:00
|
|
|
const size_t memlen_orig = chunk->memlen;
|
|
|
|
const size_t orig_alloc = CHUNK_ALLOC_SIZE(memlen_orig);
|
|
|
|
const size_t new_alloc = CHUNK_ALLOC_SIZE(sz);
|
2007-12-26 01:12:08 +01:00
|
|
|
tor_assert(sz > chunk->memlen);
|
|
|
|
offset = chunk->data - chunk->mem;
|
2016-10-14 15:38:12 +02:00
|
|
|
chunk = tor_realloc(chunk, new_alloc);
|
2007-12-26 01:12:08 +01:00
|
|
|
chunk->memlen = sz;
|
|
|
|
chunk->data = chunk->mem + offset;
|
2014-01-03 19:56:46 +01:00
|
|
|
#ifdef DEBUG_CHUNK_ALLOC
|
2016-10-14 15:38:12 +02:00
|
|
|
tor_assert(chunk->DBG_alloc == orig_alloc);
|
|
|
|
chunk->DBG_alloc = new_alloc;
|
2014-01-03 19:56:46 +01:00
|
|
|
#endif
|
2016-10-14 15:38:12 +02:00
|
|
|
total_bytes_allocated_in_chunks += new_alloc - orig_alloc;
|
|
|
|
CHUNK_SET_SENTINEL(chunk, new_alloc);
|
2007-12-26 01:12:08 +01:00
|
|
|
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. */
|
2016-09-13 15:07:12 +02:00
|
|
|
STATIC size_t
|
2007-12-26 01:12:08 +01:00
|
|
|
preferred_chunk_size(size_t target)
|
2007-04-23 16:42:27 +02:00
|
|
|
{
|
2016-10-17 20:52:44 +02:00
|
|
|
tor_assert(target <= SIZE_T_CEILING - CHUNK_OVERHEAD);
|
2016-09-13 15:07:12 +02:00
|
|
|
if (CHUNK_ALLOC_SIZE(target) >= MAX_CHUNK_ALLOC)
|
|
|
|
return CHUNK_ALLOC_SIZE(target);
|
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
|
|
|
/** 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>.
|
2015-09-02 14:50:26 +02:00
|
|
|
*/
|
2014-01-04 19:30:56 +01:00
|
|
|
STATIC void
|
2015-09-01 20:36:25 +02:00
|
|
|
buf_pullup(buf_t *buf, size_t bytes)
|
2007-12-26 01:12:08 +01:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
2015-09-01 20:36:25 +02:00
|
|
|
capacity = bytes;
|
|
|
|
if (buf->head->datalen >= bytes)
|
|
|
|
return;
|
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.*/
|
2011-12-14 22:38:43 +01:00
|
|
|
size_t needed = capacity - buf->head->datalen;
|
|
|
|
if (CHUNK_REMAINING_CAPACITY(buf->head) < needed)
|
2007-12-26 01:12:08 +01:00
|
|
|
chunk_repack(buf->head);
|
2011-12-14 22:38:43 +01:00
|
|
|
tor_assert(CHUNK_REMAINING_CAPACITY(buf->head) >= needed);
|
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);
|
2015-03-03 22:20:17 +01:00
|
|
|
if (n >= src->datalen) {
|
2007-12-26 01:12:08 +01:00
|
|
|
memcpy(CHUNK_WRITE_PTR(dest), src->data, src->datalen);
|
|
|
|
dest->datalen += src->datalen;
|
|
|
|
dest->next = src->next;
|
|
|
|
if (buf->tail == src)
|
|
|
|
buf->tail = dest;
|
2016-04-15 18:20:14 +02:00
|
|
|
buf_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
|
|
|
|
|
|
|
check();
|
2003-10-14 03:34:31 +02:00
|
|
|
}
|
|
|
|
|
2014-01-04 19:30:56 +01:00
|
|
|
#ifdef TOR_UNIT_TESTS
|
|
|
|
void
|
|
|
|
buf_get_first_chunk_data(const buf_t *buf, const char **cp, size_t *sz)
|
|
|
|
{
|
|
|
|
if (!buf || !buf->head) {
|
|
|
|
*cp = NULL;
|
|
|
|
*sz = 0;
|
|
|
|
} else {
|
|
|
|
*cp = buf->head->data;
|
|
|
|
*sz = buf->head->datalen;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-06-11 23:17:38 +02:00
|
|
|
/** Remove the first <b>n</b> bytes from buf. */
|
2015-12-10 16:19:43 +01: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;
|
2016-04-15 18:20:14 +02:00
|
|
|
buf_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
|
|
|
|
2014-01-04 19:30:56 +01:00
|
|
|
size_t
|
|
|
|
buf_get_default_chunk_size(const buf_t *buf)
|
|
|
|
{
|
|
|
|
return buf->default_chunk_size;
|
|
|
|
}
|
|
|
|
|
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;
|
2016-04-15 18:20:14 +02:00
|
|
|
buf_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> */
|
2014-01-23 15:42:14 +01:00
|
|
|
MOCK_IMPL(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) {
|
2013-11-20 17:56:35 +01:00
|
|
|
total += CHUNK_ALLOC_SIZE(chunk->memlen);
|
2007-12-26 01:12:08 +01:00
|
|
|
}
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2011-07-18 21:36:20 +02:00
|
|
|
/** Return a new copy of <b>in_chunk</b> */
|
|
|
|
static chunk_t *
|
|
|
|
chunk_copy(const chunk_t *in_chunk)
|
|
|
|
{
|
|
|
|
chunk_t *newch = tor_memdup(in_chunk, CHUNK_ALLOC_SIZE(in_chunk->memlen));
|
2014-01-03 19:56:46 +01:00
|
|
|
total_bytes_allocated_in_chunks += CHUNK_ALLOC_SIZE(in_chunk->memlen);
|
2014-01-03 19:56:46 +01:00
|
|
|
#ifdef DEBUG_CHUNK_ALLOC
|
|
|
|
newch->DBG_alloc = CHUNK_ALLOC_SIZE(in_chunk->memlen);
|
|
|
|
#endif
|
2011-07-18 21:36:20 +02:00
|
|
|
newch->next = NULL;
|
|
|
|
if (in_chunk->data) {
|
|
|
|
off_t offset = in_chunk->data - in_chunk->mem;
|
|
|
|
newch->data = newch->mem + offset;
|
|
|
|
}
|
|
|
|
return newch;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Return a new copy of <b>buf</b> */
|
|
|
|
buf_t *
|
|
|
|
buf_copy(const buf_t *buf)
|
|
|
|
{
|
|
|
|
chunk_t *ch;
|
|
|
|
buf_t *out = buf_new();
|
|
|
|
out->default_chunk_size = buf->default_chunk_size;
|
|
|
|
for (ch = buf->head; ch; ch = ch->next) {
|
|
|
|
chunk_t *newch = chunk_copy(ch);
|
|
|
|
if (out->tail) {
|
|
|
|
out->tail->next = newch;
|
|
|
|
out->tail = newch;
|
|
|
|
} else {
|
|
|
|
out->head = out->tail = newch;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
out->datalen = buf->datalen;
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
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;
|
2016-07-08 21:24:21 +02:00
|
|
|
|
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
|
|
|
}
|
2013-11-16 00:38:52 +01:00
|
|
|
|
2016-07-08 21:24:21 +02:00
|
|
|
chunk->inserted_time = (uint32_t)monotime_coarse_absolute_msec();
|
2013-11-16 00:38:52 +01: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
|
|
|
}
|
|
|
|
|
2013-11-16 00:38:52 +01:00
|
|
|
/** Return the age of the oldest chunk in the buffer <b>buf</b>, in
|
2016-07-08 21:24:21 +02:00
|
|
|
* milliseconds. Requires the current monotonic time, in truncated msec,
|
|
|
|
* as its input <b>now</b>.
|
2013-11-16 00:38:52 +01:00
|
|
|
*/
|
|
|
|
uint32_t
|
|
|
|
buf_get_oldest_chunk_timestamp(const buf_t *buf, uint32_t now)
|
|
|
|
{
|
|
|
|
if (buf->head) {
|
|
|
|
return now - buf->head->inserted_time;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t
|
|
|
|
buf_get_total_allocation(void)
|
|
|
|
{
|
|
|
|
return total_bytes_allocated_in_chunks;
|
|
|
|
}
|
|
|
|
|
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. */
|
2015-12-10 16:19:43 +01:00
|
|
|
static inline int
|
2011-05-23 06:17:48 +02:00
|
|
|
read_to_chunk(buf_t *buf, chunk_t *chunk, tor_socket_t 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 */
|
2012-01-31 16:59:42 +01:00
|
|
|
#ifdef _WIN32
|
2006-04-08 09:54:11 +02:00
|
|
|
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. */
|
2015-12-10 16:19:43 +01:00
|
|
|
static inline int
|
2007-12-26 01:12:08 +01:00
|
|
|
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
|
|
|
*/
|
2016-05-30 22:18:16 +02:00
|
|
|
/* XXXX indicate "read blocked" somehow? */
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
2011-05-23 06:17:48 +02:00
|
|
|
read_to_buf(tor_socket_t s, size_t at_most, buf_t *buf, int *reached_eof,
|
2008-09-14 10:35:41 +02:00
|
|
|
int *socket_error)
|
2005-04-26 22:53:22 +02:00
|
|
|
{
|
2016-05-30 22:18:16 +02:00
|
|
|
/* XXXX It's stupid to overload the return values for these functions:
|
2008-02-06 20:34:32 +01:00
|
|
|
* "error status" and "number of bytes read" are not mutually exclusive.
|
|
|
|
*/
|
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);
|
2012-01-17 22:35:07 +01:00
|
|
|
tor_assert(SOCKET_OK(s));
|
2007-12-26 01:12:08 +01: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;
|
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;
|
2012-02-22 09:29:16 +01:00
|
|
|
|
|
|
|
check_no_tls_errors();
|
|
|
|
|
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);
|
2014-09-18 20:03:49 +02: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;
|
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
|
|
|
*/
|
2015-12-10 16:19:43 +01:00
|
|
|
static inline int
|
2011-05-23 06:17:48 +02:00
|
|
|
flush_chunk(tor_socket_t 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 */
|
2012-01-31 16:59:42 +01:00
|
|
|
#ifdef _WIN32
|
2006-04-08 09:54:11 +02:00
|
|
|
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
|
|
|
*/
|
2015-12-10 16:19:43 +01:00
|
|
|
static inline int
|
2007-12-26 01:12:08 +01:00
|
|
|
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
|
2011-05-23 06:17:48 +02:00
|
|
|
flush_buf(tor_socket_t s, buf_t *buf, size_t sz, size_t *buf_flushlen)
|
2003-09-25 07:17:11 +02:00
|
|
|
{
|
2016-05-30 22:18:16 +02:00
|
|
|
/* XXXX It's stupid to overload the return values for these functions:
|
2008-02-06 20:34:32 +01:00
|
|
|
* "error status" and "number of bytes flushed" are not mutually exclusive.
|
|
|
|
*/
|
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);
|
2012-01-17 22:35:07 +01:00
|
|
|
tor_assert(SOCKET_OK(s));
|
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
|
|
|
*/
|
2015-12-10 16:19:43 +01: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
|
|
|
}
|
|
|
|
|
2011-10-11 17:30:01 +02:00
|
|
|
/** True iff the cell command <b>command</b> is one that implies a
|
|
|
|
* variable-length cell in Tor link protocol <b>linkproto</b>. */
|
2015-12-10 16:19:43 +01:00
|
|
|
static inline int
|
2011-09-13 16:03:09 +02:00
|
|
|
cell_command_is_var_length(uint8_t command, int linkproto)
|
|
|
|
{
|
2011-10-11 17:30:01 +02:00
|
|
|
/* If linkproto is v2 (2), CELL_VERSIONS is the only 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.
|
2011-09-13 16:03:09 +02:00
|
|
|
*/
|
|
|
|
switch (linkproto) {
|
|
|
|
case 1:
|
|
|
|
/* Link protocol version 1 has no variable-length cells. */
|
|
|
|
return 0;
|
|
|
|
case 2:
|
|
|
|
/* In link protocol version 2, VERSIONS is the only variable-length cell */
|
|
|
|
return command == CELL_VERSIONS;
|
|
|
|
case 0:
|
|
|
|
case 3:
|
|
|
|
default:
|
|
|
|
/* In link protocol version 3 and later, and in version "unknown",
|
|
|
|
* commands 128 and higher indicate variable-length. VERSIONS is
|
|
|
|
* grandfathered in. */
|
|
|
|
return command == CELL_VERSIONS || command >= 128;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2012-11-07 01:56:47 +01:00
|
|
|
char hdr[VAR_CELL_MAX_HEADER_SIZE];
|
2007-11-05 22:46:35 +01:00
|
|
|
var_cell_t *result;
|
|
|
|
uint8_t command;
|
|
|
|
uint16_t length;
|
2012-11-07 01:56:47 +01:00
|
|
|
const int wide_circ_ids = linkproto >= MIN_LINK_PROTO_FOR_WIDE_CIRC_IDS;
|
2013-02-09 06:56:53 +01:00
|
|
|
const int circ_id_len = get_circ_id_size(wide_circ_ids);
|
|
|
|
const unsigned header_len = get_var_cell_header_size(wide_circ_ids);
|
2007-11-05 22:46:35 +01:00
|
|
|
check();
|
|
|
|
*out = NULL;
|
2012-11-07 01:56:47 +01:00
|
|
|
if (buf->datalen < header_len)
|
2007-11-05 22:46:35 +01:00
|
|
|
return 0;
|
2013-02-16 00:20:46 +01:00
|
|
|
peek_from_buf(hdr, header_len, buf);
|
2007-11-05 22:46:35 +01:00
|
|
|
|
2012-11-07 01:56:47 +01:00
|
|
|
command = get_uint8(hdr + circ_id_len);
|
2011-09-13 16:03:09 +02:00
|
|
|
if (!(cell_command_is_var_length(command, linkproto)))
|
2007-11-05 22:46:35 +01:00
|
|
|
return 0;
|
|
|
|
|
2012-11-07 01:56:47 +01:00
|
|
|
length = ntohs(get_uint16(hdr + circ_id_len + 1));
|
|
|
|
if (buf->datalen < (size_t)(header_len+length))
|
2007-11-05 22:46:35 +01:00
|
|
|
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;
|
2012-11-07 01:56:47 +01:00
|
|
|
if (wide_circ_ids)
|
|
|
|
result->circ_id = ntohl(get_uint32(hdr));
|
|
|
|
else
|
|
|
|
result->circ_id = ntohs(get_uint16(hdr));
|
2007-11-05 22:46:35 +01:00
|
|
|
|
2012-11-07 01:56:47 +01:00
|
|
|
buf_remove_from_front(buf, header_len);
|
2010-12-14 01:34:01 +01:00
|
|
|
peek_from_buf((char*) result->payload, length, buf);
|
2007-11-05 22:46:35 +01:00
|
|
|
buf_remove_from_front(buf, length);
|
|
|
|
check();
|
|
|
|
|
|
|
|
*out = result;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
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. */
|
2015-12-10 16:19:43 +01:00
|
|
|
static inline int
|
2007-12-29 18:36:03 +01:00
|
|
|
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. */
|
2013-06-06 23:58:28 +02:00
|
|
|
STATIC 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)
|
2015-09-01 20:36:25 +02:00
|
|
|
buf_pullup(buf, crlf_offset+4);
|
2007-12-29 18:36:03 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
2011-06-14 19:01:38 +02:00
|
|
|
const or_options_t *options = get_options();
|
2010-10-04 13:31:58 +02:00
|
|
|
if (! options->WarnUnsafeSocks)
|
|
|
|
return;
|
2012-12-26 17:07:15 +01:00
|
|
|
if (safe_socks) {
|
|
|
|
log_fn_ratelim(&socks_ratelim, LOG_WARN, LD_APP,
|
2010-10-04 13:31:58 +02:00
|
|
|
"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/"
|
2012-12-26 17:07:15 +01:00
|
|
|
"TorFAQ#SOCKSAndDNS.%s",
|
2010-10-04 13:31:58 +02:00
|
|
|
socks_protocol,
|
|
|
|
(int)port,
|
2012-12-26 17:07:15 +01:00
|
|
|
safe_socks ? " Rejecting." : "");
|
2010-10-04 13:31:58 +02:00
|
|
|
}
|
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
|
|
|
}
|
|
|
|
|
2011-01-10 23:24:16 +01:00
|
|
|
/** Do not attempt to parse socks messages longer than this. This value is
|
|
|
|
* actually significantly higher than the longest possible socks message. */
|
|
|
|
#define MAX_SOCKS_MESSAGE_LEN 512
|
|
|
|
|
2011-06-29 18:31:17 +02:00
|
|
|
/** Return a new socks_request_t. */
|
|
|
|
socks_request_t *
|
|
|
|
socks_request_new(void)
|
|
|
|
{
|
|
|
|
return tor_malloc_zero(sizeof(socks_request_t));
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Free all storage held in the socks_request_t <b>req</b>. */
|
|
|
|
void
|
|
|
|
socks_request_free(socks_request_t *req)
|
|
|
|
{
|
|
|
|
if (!req)
|
|
|
|
return;
|
2011-08-06 01:07:33 +02:00
|
|
|
if (req->username) {
|
2012-11-07 22:09:58 +01:00
|
|
|
memwipe(req->username, 0x10, req->usernamelen);
|
2011-08-06 01:07:33 +02:00
|
|
|
tor_free(req->username);
|
|
|
|
}
|
|
|
|
if (req->password) {
|
2012-11-07 22:09:58 +01:00
|
|
|
memwipe(req->password, 0x04, req->passwordlen);
|
2011-08-06 01:07:33 +02:00
|
|
|
tor_free(req->password);
|
|
|
|
}
|
2012-11-07 22:09:58 +01:00
|
|
|
memwipe(req, 0xCC, sizeof(socks_request_t));
|
2011-06-29 18:31:17 +02:00
|
|
|
tor_free(req);
|
|
|
|
}
|
|
|
|
|
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;
|
2015-09-01 20:36:25 +02:00
|
|
|
buf_pullup(buf, want_length);
|
2009-07-31 23:03:35 +02:00
|
|
|
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);
|
|
|
|
|
2011-07-12 16:51:31 +02:00
|
|
|
} while (res == 0 && buf->head && want_length < buf->datalen &&
|
|
|
|
buf->datalen >= 2);
|
2009-07-31 23:03:35 +02:00
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2012-03-24 06:05:48 +01:00
|
|
|
/** The size of the header of an Extended ORPort message: 2 bytes for
|
|
|
|
* COMMAND, 2 bytes for BODYLEN */
|
2012-03-16 14:40:44 +01:00
|
|
|
#define EXT_OR_CMD_HEADER_SIZE 4
|
2012-03-24 06:05:48 +01:00
|
|
|
|
|
|
|
/** Read <b>buf</b>, which should contain an Extended ORPort message
|
|
|
|
* from a transport proxy. If well-formed, create and populate
|
|
|
|
* <b>out</b> with the Extended ORport message. Return 0 if the
|
|
|
|
* buffer was incomplete, 1 if it was well-formed and -1 if we
|
|
|
|
* encountered an error while parsing it. */
|
2012-03-16 14:40:44 +01:00
|
|
|
int
|
|
|
|
fetch_ext_or_command_from_buf(buf_t *buf, ext_or_cmd_t **out)
|
|
|
|
{
|
|
|
|
char hdr[EXT_OR_CMD_HEADER_SIZE];
|
|
|
|
uint16_t len;
|
|
|
|
|
|
|
|
check();
|
|
|
|
if (buf->datalen < EXT_OR_CMD_HEADER_SIZE)
|
|
|
|
return 0;
|
|
|
|
peek_from_buf(hdr, sizeof(hdr), buf);
|
|
|
|
len = ntohs(get_uint16(hdr+2));
|
|
|
|
if (buf->datalen < (unsigned)len + EXT_OR_CMD_HEADER_SIZE)
|
|
|
|
return 0;
|
|
|
|
*out = ext_or_cmd_new(len);
|
|
|
|
(*out)->cmd = ntohs(get_uint16(hdr));
|
|
|
|
(*out)->len = len;
|
|
|
|
buf_remove_from_front(buf, EXT_OR_CMD_HEADER_SIZE);
|
|
|
|
fetch_from_buf((*out)->body, len, buf);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2014-09-21 18:17:44 +02:00
|
|
|
/** Create a SOCKS5 reply message with <b>reason</b> in its REP field and
|
|
|
|
* have Tor send it as error response to <b>req</b>.
|
|
|
|
*/
|
|
|
|
static void
|
2014-09-29 15:17:20 +02:00
|
|
|
socks_request_set_socks5_error(socks_request_t *req,
|
2014-09-21 18:17:44 +02:00
|
|
|
socks5_reply_status_t reason)
|
|
|
|
{
|
|
|
|
req->replylen = 10;
|
|
|
|
memset(req->reply,0,10);
|
|
|
|
|
|
|
|
req->reply[0] = 0x05; // VER field.
|
|
|
|
req->reply[1] = reason; // REP field.
|
|
|
|
req->reply[3] = 0x01; // ATYP field.
|
|
|
|
}
|
|
|
|
|
2009-07-31 23:03:35 +02:00
|
|
|
/** 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-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
|
|
|
|
2011-07-12 16:51:31 +02:00
|
|
|
if (datalen < 2) {
|
|
|
|
/* We always need at least 2 bytes. */
|
|
|
|
*want_length_out = 2;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-06-29 18:00:00 +02:00
|
|
|
if (req->socks_version == 5 && !req->got_auth) {
|
|
|
|
/* See if we have received authentication. Strictly speaking, we should
|
|
|
|
also check whether we actually negotiated username/password
|
|
|
|
authentication. But some broken clients will send us authentication
|
|
|
|
even if we negotiated SOCKS_NO_AUTH. */
|
|
|
|
if (*data == 1) { /* username/pass version 1 */
|
2011-06-29 17:45:15 +02:00
|
|
|
/* Format is: authversion [1 byte] == 1
|
|
|
|
usernamelen [1 byte]
|
|
|
|
username [usernamelen bytes]
|
|
|
|
passlen [1 byte]
|
|
|
|
password [passlen bytes] */
|
2010-10-17 15:14:51 +02:00
|
|
|
usernamelen = (unsigned char)*(data + 1);
|
2011-06-29 17:45:15 +02:00
|
|
|
if (datalen < 2u + usernamelen + 1u) {
|
|
|
|
*want_length_out = 2u + usernamelen + 1u;
|
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) {
|
2011-06-29 17:45:15 +02:00
|
|
|
*want_length_out = 2u + usernamelen + 1u + passlen;
|
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 */
|
2013-05-15 09:34:37 +02:00
|
|
|
req->reply[0] = 1; /* authversion == 1 */
|
2010-08-03 23:28:55 +02:00
|
|
|
req->reply[1] = 0; /* authentication successful */
|
|
|
|
log_debug(LD_APP,
|
|
|
|
"socks5: Accepted username/password without checking.");
|
2011-06-29 18:31:17 +02:00
|
|
|
if (usernamelen) {
|
|
|
|
req->username = tor_memdup(data+2u, usernamelen);
|
|
|
|
req->usernamelen = usernamelen;
|
|
|
|
}
|
|
|
|
if (passlen) {
|
|
|
|
req->password = tor_memdup(data+3u+usernamelen, passlen);
|
|
|
|
req->passwordlen = passlen;
|
|
|
|
}
|
2010-10-17 15:14:51 +02:00
|
|
|
*drain_out = 2u + usernamelen + 1u + passlen;
|
2011-06-29 18:00:00 +02:00
|
|
|
req->got_auth = 1;
|
2014-10-22 17:35:46 +02:00
|
|
|
*want_length_out = 7; /* Minimal socks5 command. */
|
2010-08-03 23:28:55 +02:00
|
|
|
return 0;
|
2011-06-29 18:00:00 +02:00
|
|
|
} else if (req->auth_type == SOCKS_USER_PASS) {
|
|
|
|
/* unknown version byte */
|
|
|
|
log_warn(LD_APP, "Socks5 username/password version %d not recognized; "
|
|
|
|
"rejecting.", (int)*data);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
2010-08-03 23:28:55 +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
|
|
|
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);
|
2013-03-20 21:17:06 +01:00
|
|
|
int have_user_pass, have_no_auth;
|
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 */
|
2013-03-20 21:17:06 +01:00
|
|
|
have_user_pass = (memchr(data+2, SOCKS_USER_PASS, nummethods) !=NULL);
|
|
|
|
have_no_auth = (memchr(data+2, SOCKS_NO_AUTH, nummethods) !=NULL);
|
|
|
|
if (have_user_pass && !(have_no_auth && req->socks_prefer_no_auth)) {
|
2011-06-29 18:00:00 +02:00
|
|
|
req->auth_type = SOCKS_USER_PASS;
|
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;
|
2013-03-20 21:17:06 +01:00
|
|
|
} else if (have_no_auth) {
|
2013-03-20 20:37:47 +01: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-08-03 23:28:55 +02:00
|
|
|
} 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
|
|
|
}
|
2011-06-29 23:29:33 +02:00
|
|
|
/* Remove packet from buf. Some SOCKS clients will have sent extra
|
|
|
|
* junk at this point; let's hope it's an authentication message. */
|
|
|
|
*drain_out = 2u + nummethods;
|
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
|
|
|
}
|
2011-06-29 18:16:09 +02:00
|
|
|
if (req->auth_type != SOCKS_NO_AUTH && !req->got_auth) {
|
|
|
|
log_warn(LD_APP,
|
|
|
|
"socks5: negotiated authentication, but none provided");
|
|
|
|
return -1;
|
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");
|
2011-06-29 23:44:29 +02:00
|
|
|
if (datalen < 7) {/* basic info plus >=1 for addr plus 2 for port */
|
|
|
|
*want_length_out = 7;
|
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. */
|
2014-09-29 15:17:20 +02:00
|
|
|
socks_request_set_socks5_error(req,SOCKS5_COMMAND_NOT_SUPPORTED);
|
2014-09-21 18:17:44 +02:00
|
|
|
|
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) {
|
2014-10-01 16:16:59 +02:00
|
|
|
socks_request_set_socks5_error(req, SOCKS5_GENERAL_ERROR);
|
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);
|
2014-10-01 16:16:59 +02:00
|
|
|
if (safe_socks) {
|
|
|
|
socks_request_set_socks5_error(req, SOCKS5_NOT_ALLOWED);
|
2006-03-19 02:44:53 +01:00
|
|
|
return -1;
|
2014-10-01 16:16:59 +02:00
|
|
|
}
|
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) {
|
2014-10-01 16:16:59 +02:00
|
|
|
socks_request_set_socks5_error(req,
|
|
|
|
SOCKS5_ADDRESS_TYPE_NOT_SUPPORTED);
|
2007-05-15 23:17:48 +02:00
|
|
|
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) {
|
2014-10-01 16:16:59 +02:00
|
|
|
socks_request_set_socks5_error(req, SOCKS5_GENERAL_ERROR);
|
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;
|
2014-10-12 20:04:15 +02:00
|
|
|
|
2014-10-14 20:56:04 +02:00
|
|
|
if (string_is_valid_ipv4_address(req->address) ||
|
|
|
|
string_is_valid_ipv6_address(req->address)) {
|
2014-10-12 20:04:15 +02:00
|
|
|
log_unsafe_socks_warning(5,req->address,req->port,safe_socks);
|
|
|
|
|
2014-10-21 19:50:32 +02:00
|
|
|
if (safe_socks) {
|
|
|
|
socks_request_set_socks5_error(req, SOCKS5_NOT_ALLOWED);
|
2014-10-12 20:04:15 +02:00
|
|
|
return -1;
|
2014-10-21 19:50:32 +02:00
|
|
|
}
|
2014-12-30 17:36:16 +01:00
|
|
|
} else if (!string_is_valid_hostname(req->address)) {
|
2014-10-01 16:16:59 +02:00
|
|
|
socks_request_set_socks5_error(req, SOCKS5_GENERAL_ERROR);
|
2014-11-04 06:48:25 +01:00
|
|
|
|
2006-03-16 00:36:57 +01:00
|
|
|
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.",
|
2015-08-24 01:04:44 +02:00
|
|
|
req->port, escaped_safe_str_client(req->address));
|
2006-03-16 00:36:57 +01:00
|
|
|
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,
|
2011-09-28 18:00:59 +02:00
|
|
|
"Your application (using socks5 to port %d) instructed "
|
|
|
|
"Tor to take care of the DNS resolution itself if "
|
|
|
|
"necessary. This is good.", req->port);
|
2003-10-04 03:37:01 +02:00
|
|
|
return 1;
|
|
|
|
default: /* unsupported */
|
2014-10-01 16:16:59 +02:00
|
|
|
socks_request_set_socks5_error(req,
|
|
|
|
SOCKS5_ADDRESS_TYPE_NOT_SUPPORTED);
|
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);
|
2017-05-28 23:49:31 +02:00
|
|
|
break;
|
2011-06-29 18:31:17 +02:00
|
|
|
case 4: { /* socks4 */
|
|
|
|
enum {socks4, socks4a} socks4_prot = socks4a;
|
|
|
|
const char *authstart, *authend;
|
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
|
|
|
}
|
2015-09-01 20:36:25 +02:00
|
|
|
// buf_pullup(buf, 1280);
|
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 &&
|
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;
|
|
|
|
}
|
|
|
|
|
2011-06-29 18:31:17 +02:00
|
|
|
authstart = data + SOCKS4_NETWORK_LEN;
|
|
|
|
next = memchr(authstart, 0,
|
2009-07-31 23:03:35 +02:00
|
|
|
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.");
|
2011-06-29 23:44:29 +02:00
|
|
|
*want_length_out = datalen+1024; /* More than we need, but safe */
|
2003-10-04 03:37:01 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2011-06-29 18:31:17 +02:00
|
|
|
authend = next;
|
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.");
|
2011-06-29 23:44:29 +02:00
|
|
|
*want_length_out = datalen + 1024; /* More than we need, but safe */
|
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,
|
2011-09-28 18:00:59 +02:00
|
|
|
"Your application (using socks4a to port %d) instructed "
|
|
|
|
"Tor to take care of the DNS resolution itself if "
|
|
|
|
"necessary. 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.",
|
2016-01-12 16:42:01 +01:00
|
|
|
req->port, escaped_safe_str_client(req->address));
|
2006-03-16 00:36:57 +01:00
|
|
|
return -1;
|
|
|
|
}
|
2011-06-29 18:31:17 +02:00
|
|
|
if (authend != authstart) {
|
|
|
|
req->got_auth = 1;
|
|
|
|
req->usernamelen = authend - authstart;
|
|
|
|
req->username = tor_memdup(authstart, authend - authstart);
|
|
|
|
}
|
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;
|
2011-06-29 18:31:17 +02:00
|
|
|
}
|
2004-02-26 23:02:22 +01:00
|
|
|
case 'G': /* get */
|
|
|
|
case 'H': /* head */
|
|
|
|
case 'P': /* put/post */
|
|
|
|
case 'C': /* connect */
|
2011-06-29 18:00:00 +02:00
|
|
|
strlcpy((char*)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);
|
2011-06-29 18:00:00 +02:00
|
|
|
req->replylen = strlen((char*)req->reply)+1;
|
2004-02-26 23:02:22 +01:00
|
|
|
/* 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;
|
|
|
|
|
2015-09-01 20:36:25 +02:00
|
|
|
buf_pullup(buf, MAX_SOCKS_MESSAGE_LEN);
|
2009-06-19 01:59:18 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** 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
|
|
|
}
|
|
|
|
|
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;
|
2014-05-08 18:40:40 +02:00
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2011-07-18 21:36:20 +02:00
|
|
|
/** Set *<b>output</b> to contain a copy of the data in *<b>input</b> */
|
|
|
|
int
|
2016-08-02 19:40:19 +02:00
|
|
|
buf_set_to_copy(buf_t **output,
|
|
|
|
const buf_t *input)
|
2011-07-18 21:36:20 +02:00
|
|
|
{
|
|
|
|
if (*output)
|
|
|
|
buf_free(*output);
|
|
|
|
*output = buf_copy(input);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
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]);
|
2015-03-03 22:25:26 +01:00
|
|
|
tor_assert(ch->data <= &ch->mem[0]+ch->memlen);
|
|
|
|
if (ch->data == &ch->mem[0]+ch->memlen) {
|
|
|
|
static int warned = 0;
|
|
|
|
if (! warned) {
|
|
|
|
log_warn(LD_BUG, "Invariant violation in buf.c related to #15083");
|
|
|
|
warned = 1;
|
|
|
|
}
|
|
|
|
}
|
2007-12-26 01:12:08 +01:00
|
|
|
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
|
|
|
|