123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699 |
- const char buffers_c_id[] = "$Id$";
- #include "or.h"
- #define BUFFER_MAGIC 0xB0FFF312u
- struct buf_t {
- uint32_t magic;
- char *mem;
- size_t len;
- size_t datalen;
- };
- #define INITIAL_BUF_SIZE (4*1024)
- #define MAX_BUF_SIZE (1024*1024*10)
- #define MIN_BUF_SHRINK_SIZE (16*1024)
- static INLINE void buf_resize(buf_t *buf, size_t new_capacity)
- {
- tor_assert(buf->datalen <= new_capacity);
- tor_assert(new_capacity);
- buf->mem = tor_realloc(buf->mem, new_capacity);
- buf->len = new_capacity;
- }
- static INLINE int buf_ensure_capacity(buf_t *buf, size_t capacity)
- {
- size_t new_len;
- if (buf->len >= capacity)
- return 0;
- if (capacity > MAX_BUF_SIZE)
- return -1;
-
- new_len = buf->len*2;
- while (new_len < capacity)
- new_len *= 2;
-
- log_fn(LOG_DEBUG,"Growing buffer from %d to %d bytes.",
- (int)buf->len, (int)new_len);
- buf_resize(buf,new_len);
- return 0;
- }
- static INLINE void buf_shrink_if_underfull(buf_t *buf) {
- size_t new_len;
-
- if (buf->datalen >= buf->len/4 || buf->len < 2*MIN_BUF_SHRINK_SIZE)
- return;
-
- new_len = buf->len / 2;
- while (buf->datalen < new_len/4 && new_len/2 > MIN_BUF_SHRINK_SIZE)
- new_len /= 2;
- log_fn(LOG_DEBUG,"Shrinking buffer from %d to %d bytes.",
- (int)buf->len, (int)new_len);
- buf_resize(buf, new_len);
- }
- static INLINE void buf_remove_from_front(buf_t *buf, size_t n) {
- tor_assert(buf->datalen >= n);
- buf->datalen -= n;
- memmove(buf->mem, buf->mem+n, buf->datalen);
- buf_shrink_if_underfull(buf);
- }
- static INLINE int buf_nul_terminate(buf_t *buf)
- {
- if (buf_ensure_capacity(buf,buf->datalen+1)<0)
- return -1;
- buf->mem[buf->datalen] = '\0';
- return 0;
- }
- buf_t *buf_new_with_capacity(size_t size) {
- buf_t *buf;
- buf = tor_malloc(sizeof(buf_t));
- buf->magic = BUFFER_MAGIC;
- buf->mem = tor_malloc(size);
- buf->len = size;
- buf->datalen = 0;
- assert_buf_ok(buf);
- return buf;
- }
- buf_t *buf_new()
- {
- return buf_new_with_capacity(INITIAL_BUF_SIZE);
- }
- void buf_clear(buf_t *buf)
- {
- buf->datalen = 0;
- }
- size_t buf_datalen(const buf_t *buf)
- {
- return buf->datalen;
- }
- size_t buf_capacity(const buf_t *buf)
- {
- return buf->len;
- }
- const char *_buf_peek_raw_buffer(const buf_t *buf)
- {
- return buf->mem;
- }
- void buf_free(buf_t *buf) {
- assert_buf_ok(buf);
- buf->magic = 0xDEADBEEF;
- tor_free(buf->mem);
- tor_free(buf);
- }
- int read_to_buf(int s, size_t at_most, buf_t *buf, int *reached_eof) {
- int read_result;
- assert_buf_ok(buf);
- tor_assert(reached_eof);
- tor_assert(s>=0);
- if (buf_ensure_capacity(buf,buf->datalen+at_most))
- return -1;
- if (at_most + buf->datalen > buf->len)
- at_most = buf->len - buf->datalen;
- if (at_most == 0)
- return 0;
- read_result = recv(s, buf->mem+buf->datalen, at_most, 0);
- if (read_result < 0) {
- int e = tor_socket_errno(s);
- if (!ERRNO_IS_EAGAIN(e)) {
- return -1;
- }
- return 0;
- } else if (read_result == 0) {
- log_fn(LOG_DEBUG,"Encountered eof");
- *reached_eof = 1;
- return 0;
- } else {
- buf->datalen += read_result;
- log_fn(LOG_DEBUG,"Read %d bytes. %d on inbuf.",read_result,
- (int)buf->datalen);
- return read_result;
- }
- }
- int read_to_buf_tls(tor_tls *tls, size_t at_most, buf_t *buf) {
- int r;
- tor_assert(tls);
- assert_buf_ok(buf);
- log_fn(LOG_DEBUG,"start: %d on buf, %d pending, at_most %d.",
- (int)buf_datalen(buf), (int)tor_tls_get_pending_bytes(tls),
- (int)at_most);
- if (buf_ensure_capacity(buf, at_most+buf->datalen))
- return TOR_TLS_ERROR;
- if (at_most + buf->datalen > buf->len)
- at_most = buf->len - buf->datalen;
- if (at_most == 0)
- return 0;
- log_fn(LOG_DEBUG,"before: %d on buf, %d pending, at_most %d.",
- (int)buf_datalen(buf), (int)tor_tls_get_pending_bytes(tls),
- (int)at_most);
- assert_no_tls_errors();
- r = tor_tls_read(tls, buf->mem+buf->datalen, at_most);
- if (r<0)
- return r;
- buf->datalen += r;
- log_fn(LOG_DEBUG,"Read %d bytes. %d on inbuf; %d pending",r,
- (int)buf->datalen,(int)tor_tls_get_pending_bytes(tls));
- return r;
- }
- int flush_buf(int s, buf_t *buf, size_t *buf_flushlen)
- {
- int write_result;
- assert_buf_ok(buf);
- tor_assert(buf_flushlen);
- tor_assert(s>=0);
- tor_assert(*buf_flushlen <= buf->datalen);
- if (*buf_flushlen == 0)
- return 0;
- write_result = send(s, buf->mem, *buf_flushlen, 0);
- if (write_result < 0) {
- int e = tor_socket_errno(s);
- if (!ERRNO_IS_EAGAIN(e)) {
- return -1;
- }
- log_fn(LOG_DEBUG,"write() would block, returning.");
- return 0;
- } else {
- *buf_flushlen -= write_result;
- log_fn(LOG_DEBUG,"%d: flushed %d bytes, %d ready to flush, %d remain.",
- s,write_result,(int)*buf_flushlen,(int)buf->datalen);
- buf_remove_from_front(buf, write_result);
- return write_result;
- }
- }
- int flush_buf_tls(tor_tls *tls, buf_t *buf, size_t *buf_flushlen)
- {
- int r;
- assert_buf_ok(buf);
- tor_assert(tls);
- tor_assert(buf_flushlen);
-
- r = tor_tls_write(tls, buf->mem, *buf_flushlen);
- if (r < 0) {
- return r;
- }
- *buf_flushlen -= r;
- buf_remove_from_front(buf, r);
- log_fn(LOG_DEBUG,"flushed %d bytes, %d ready to flush, %d remain.",
- r,(int)*buf_flushlen,(int)buf->datalen);
- return r;
- }
- int write_to_buf(const char *string, size_t string_len, buf_t *buf) {
-
- tor_assert(string);
- assert_buf_ok(buf);
- if (buf_ensure_capacity(buf, buf->datalen+string_len)) {
- log_fn(LOG_WARN, "buflen too small, can't hold %d bytes.", (int)(buf->datalen+string_len));
- return -1;
- }
- memcpy(buf->mem+buf->datalen, string, string_len);
- buf->datalen += string_len;
- log_fn(LOG_DEBUG,"added %d bytes to buf (now %d total).",(int)string_len, (int)buf->datalen);
- return buf->datalen;
- }
- int fetch_from_buf(char *string, size_t string_len, buf_t *buf) {
-
- tor_assert(string);
- tor_assert(string_len <= buf->datalen);
- assert_buf_ok(buf);
- memcpy(string,buf->mem,string_len);
- buf_remove_from_front(buf, string_len);
- return buf->datalen;
- }
- int fetch_from_buf_http(buf_t *buf,
- char **headers_out, size_t max_headerlen,
- char **body_out, size_t *body_used, size_t max_bodylen) {
- char *headers, *body, *p;
- size_t headerlen, bodylen, contentlen;
- assert_buf_ok(buf);
- headers = buf->mem;
- if (buf_nul_terminate(buf)<0) {
- log_fn(LOG_WARN,"Couldn't nul-terminate buffer");
- return -1;
- }
- body = strstr(headers,"\r\n\r\n");
- if (!body) {
- log_fn(LOG_DEBUG,"headers not all here yet.");
- return 0;
- }
- body += 4;
- headerlen = body-headers;
- bodylen = buf->datalen - headerlen;
- log_fn(LOG_DEBUG,"headerlen %d, bodylen %d.", (int)headerlen, (int)bodylen);
- if (max_headerlen <= headerlen) {
- log_fn(LOG_WARN,"headerlen %d larger than %d. Failing.", (int)headerlen,
- (int)max_headerlen-1);
- return -1;
- }
- if (max_bodylen <= bodylen) {
- log_fn(LOG_WARN,"bodylen %d larger than %d. Failing.", (int)bodylen, (int)max_bodylen-1);
- return -1;
- }
- #define CONTENT_LENGTH "\r\nContent-Length: "
- p = strstr(headers, CONTENT_LENGTH);
- if (p) {
- int i;
- i = atoi(p+strlen(CONTENT_LENGTH));
- if (i < 0) {
- log_fn(LOG_WARN, "Content-Length is less than zero; it looks like someone is trying to crash us.");
- return -1;
- }
- contentlen = i;
-
- log_fn(LOG_DEBUG,"Got a contentlen of %d.",(int)contentlen);
- if (bodylen < contentlen) {
- log_fn(LOG_DEBUG,"body not all here yet.");
- return 0;
- }
- if (bodylen > contentlen) {
- bodylen = contentlen;
- log_fn(LOG_DEBUG,"bodylen reduced to %d.",(int)bodylen);
- }
- }
-
- if (headers_out) {
- *headers_out = tor_malloc(headerlen+1);
- memcpy(*headers_out,buf->mem,headerlen);
- (*headers_out)[headerlen] = 0;
- }
- if (body_out) {
- tor_assert(body_used);
- *body_used = bodylen;
- *body_out = tor_malloc(bodylen+1);
- memcpy(*body_out,buf->mem+headerlen,bodylen);
- (*body_out)[bodylen] = 0;
- }
- buf_remove_from_front(buf, headerlen+bodylen);
- return 1;
- }
- int fetch_from_buf_socks(buf_t *buf, socks_request_t *req) {
- unsigned char len;
- char *tmpbuf=NULL;
- uint32_t destip;
- enum {socks4, socks4a} socks4_prot = socks4a;
- char *next, *startaddr;
- struct in_addr in;
-
- static int have_warned_about_unsafe_socks = 0;
- if (buf->datalen < 2)
- return 0;
- switch (*(buf->mem)) {
- case 5:
- if (req->socks_version != 5) {
- unsigned char nummethods = (unsigned char)*(buf->mem+1);
- tor_assert(!req->socks_version);
- if (buf->datalen < 2u+nummethods)
- return 0;
- if (!nummethods || !memchr(buf->mem+2, 0, nummethods)) {
- log_fn(LOG_WARN,"socks5: offered methods don't include 'no auth'. Rejecting.");
- req->replylen = 2;
- req->reply[0] = 5;
- req->reply[1] = '\xFF';
- return -1;
- }
- buf_remove_from_front(buf,2+nummethods);
- req->replylen = 2;
- req->reply[0] = 5;
- req->reply[1] = 0;
- req->socks_version = 5;
- log_fn(LOG_DEBUG,"socks5: accepted method 0");
- return 0;
- }
-
- log_fn(LOG_DEBUG,"socks5: checking request");
- if (buf->datalen < 8)
- return 0;
- req->command = (unsigned char) *(buf->mem+1);
- if (req->command != SOCKS_COMMAND_CONNECT &&
- req->command != SOCKS_COMMAND_RESOLVE) {
-
- log_fn(LOG_WARN,"socks5: command %d not recognized. Rejecting.",
- req->command);
- return -1;
- }
- switch (*(buf->mem+3)) {
- case 1:
- log_fn(LOG_DEBUG,"socks5: ipv4 address type");
- if (buf->datalen < 10)
- return 0;
- destip = ntohl(*(uint32_t*)(buf->mem+4));
- in.s_addr = htonl(destip);
- tmpbuf = inet_ntoa(in);
- if (strlen(tmpbuf)+1 > MAX_SOCKS_ADDR_LEN) {
- log_fn(LOG_WARN,"socks5 IP takes %d bytes, which doesn't fit in %d. Rejecting.",
- (int)strlen(tmpbuf)+1,(int)MAX_SOCKS_ADDR_LEN);
- return -1;
- }
- strlcpy(req->address,tmpbuf,sizeof(req->address));
- req->port = ntohs(*(uint16_t*)(buf->mem+8));
- buf_remove_from_front(buf, 10);
- if (!have_warned_about_unsafe_socks) {
- log_fn(LOG_WARN,"Your application (using socks5 on 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.", req->port);
- }
- return 1;
- case 3:
- log_fn(LOG_DEBUG,"socks5: fqdn address type");
- len = (unsigned char)*(buf->mem+4);
- if (buf->datalen < 7u+len)
- return 0;
- if (len+1 > MAX_SOCKS_ADDR_LEN) {
- log_fn(LOG_WARN,"socks5 hostname is %d bytes, which doesn't fit in %d. Rejecting.",
- len+1,MAX_SOCKS_ADDR_LEN);
- return -1;
- }
- memcpy(req->address,buf->mem+5,len);
- req->address[len] = 0;
- req->port = ntohs(get_uint16(buf->mem+5+len));
- buf_remove_from_front(buf, 5+len+2);
- return 1;
- default:
- log_fn(LOG_WARN,"socks5: unsupported address type %d. Rejecting.",*(buf->mem+3));
- return -1;
- }
- tor_assert(0);
- case 4:
-
-
- req->socks_version = 4;
- if (buf->datalen < SOCKS4_NETWORK_LEN)
- return 0;
- req->command = (unsigned char) *(buf->mem+1);
- if (req->command != SOCKS_COMMAND_CONNECT &&
- req->command != SOCKS_COMMAND_RESOLVE) {
-
- log_fn(LOG_WARN,"socks4: command %d not recognized. Rejecting.",
- req->command);
- return -1;
- }
- req->port = ntohs(*(uint16_t*)(buf->mem+2));
- destip = ntohl(*(uint32_t*)(buf->mem+4));
- if ((!req->port && req->command!=SOCKS_COMMAND_RESOLVE) || !destip) {
- log_fn(LOG_WARN,"socks4: Port or DestIP is zero. Rejecting.");
- return -1;
- }
- if (destip >> 8) {
- log_fn(LOG_DEBUG,"socks4: destip not in form 0.0.0.x.");
- in.s_addr = htonl(destip);
- tmpbuf = inet_ntoa(in);
- if (strlen(tmpbuf)+1 > MAX_SOCKS_ADDR_LEN) {
- log_fn(LOG_WARN,"socks4 addr (%d bytes) too long. Rejecting.",
- (int)strlen(tmpbuf));
- return -1;
- }
- log_fn(LOG_DEBUG,"socks4: successfully read destip (%s)", tmpbuf);
- socks4_prot = socks4;
- }
- next = memchr(buf->mem+SOCKS4_NETWORK_LEN, 0,
- buf->datalen-SOCKS4_NETWORK_LEN);
- if (!next) {
- log_fn(LOG_DEBUG,"socks4: Username not here yet.");
- return 0;
- }
- tor_assert(next < buf->mem+buf->datalen);
- startaddr = NULL;
- if (socks4_prot != socks4a && !have_warned_about_unsafe_socks) {
- log_fn(LOG_WARN,"Your application (using socks4 on 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.", req->port);
- }
- if (socks4_prot == socks4a) {
- if (next+1 == buf->mem+buf->datalen) {
- log_fn(LOG_DEBUG,"socks4: No part of destaddr here yet.");
- return 0;
- }
- startaddr = next+1;
- next = memchr(startaddr, 0, buf->mem+buf->datalen-startaddr);
- if (!next) {
- log_fn(LOG_DEBUG,"socks4: Destaddr not all here yet.");
- return 0;
- }
- if (MAX_SOCKS_ADDR_LEN <= next-startaddr) {
- log_fn(LOG_WARN,"socks4: Destaddr too long. Rejecting.");
- return -1;
- }
- tor_assert(next < buf->mem+buf->datalen);
- }
- log_fn(LOG_DEBUG,"socks4: Everything is here. Success.");
- strlcpy(req->address, startaddr ? startaddr : tmpbuf,
- sizeof(req->address));
- buf_remove_from_front(buf, next-buf->mem+1);
- return 1;
- case 'G':
- case 'H':
- case 'P':
- case 'C':
- strlcpy(req->reply,
- "HTTP/1.0 501 Tor is not an HTTP Proxy\r\n"
- "Content-Type: text/html; charset=iso-8859-1\r\n\r\n"
- "<html>\n"
- "<head>\n"
- "<title>Tor is not an HTTP Proxy</title>\n"
- "</head>\n"
- "<body>\n"
- "<h1>Tor is not an HTTP Proxy</h1>\n"
- "<p>\n"
- "It appears you have configured your web browser to use Tor as an HTTP Proxy.\n"
- "This is not correct: Tor provides a SOCKS proxy. Please configure your\n"
- "client accordingly.\n"
- "</p>\n"
- "<p>\n"
- "See <a href=\"http://freehaven.net/tor/doc/tor-doc.html\">http://freehaven.net/tor/doc/tor-doc.html</a> for more information.\n"
- "<!-- 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"
- "</p>\n"
- "</body>\n"
- "</html>\n"
- , MAX_SOCKS_REPLY_LEN);
- req->replylen = strlen(req->reply)+1;
-
- default:
- log_fn(LOG_WARN,"Socks version %d not recognized. (Tor is not an http proxy.)",
- *(buf->mem));
- return -1;
- }
- }
- int fetch_from_buf_control(buf_t *buf, uint16_t *len_out, uint16_t *type_out,
- char **body_out)
- {
- uint16_t len;
- tor_assert(buf);
- tor_assert(len_out);
- tor_assert(type_out);
- tor_assert(body_out);
- if (buf->datalen < 4)
- return 0;
- len = ntohs(get_uint16(buf->mem));
- if (buf->datalen < 4 + (unsigned)len)
- return 0;
- *len_out = len;
- *type_out = ntohs(get_uint16(buf->mem+2));
- if (len) {
- *body_out = tor_malloc(len+1);
- memcpy(*body_out, buf->mem+4, len);
- (*body_out)[len] = '\0';
- } else {
- *body_out = NULL;
- }
- buf_remove_from_front(buf, 4+len);
- return 1;
- }
- void assert_buf_ok(buf_t *buf)
- {
- tor_assert(buf);
- tor_assert(buf->magic == BUFFER_MAGIC);
- tor_assert(buf->mem);
- tor_assert(buf->datalen <= buf->len);
- }
|