📄 buffers.c
字号:
"Rejecting.");
req->replylen = 2; /* 2 bytes of response */
req->reply[0] = 5;
req->reply[1] = '\xFF'; /* reject all methods */
return -1;
}
/* remove packet from buf. also remove any other extraneous
* bytes, to support broken socks clients. */
buf_clear(buf);
req->replylen = 2; /* 2 bytes of response */
req->reply[0] = 5; /* socks5 reply */
req->reply[1] = 0; /* 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");
return 0;
}
/* we know the method; read in the request */
log_debug(LD_APP,"socks5: checking request");
if (buf->datalen < 8) /* basic info plus >=2 for addr plus 2 for port */
return 0; /* not yet */
tor_assert(buf->head->datalen >= 8);
req->command = (unsigned char) *(buf->head->data+1);
if (req->command != SOCKS_COMMAND_CONNECT &&
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. */
log_warn(LD_APP,"socks5: command %d not recognized. Rejecting.",
req->command);
return -1;
}
switch (*(buf->head->data+3)) { /* address type */
case 1: /* IPv4 address */
log_debug(LD_APP,"socks5: ipv4 address type");
if (buf->datalen < 10) /* ip/port there? */
return 0; /* not yet */
destip = ntohl(*(uint32_t*)(buf->head->data+4));
in.s_addr = htonl(destip);
tor_inet_ntoa(&in,tmpbuf,sizeof(tmpbuf));
if (strlen(tmpbuf)+1 > MAX_SOCKS_ADDR_LEN) {
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);
return -1;
}
strlcpy(req->address,tmpbuf,sizeof(req->address));
req->port = ntohs(*(uint16_t*)(buf->head->data+8));
buf_remove_from_front(buf, 10);
if (req->command != SOCKS_COMMAND_RESOLVE_PTR &&
!addressmap_have_mapping(req->address) &&
!have_warned_about_unsafe_socks) {
log_warn(LD_APP,
"Your application (using socks5 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 http://wiki.noreply.org/noreply/TheOnionRouter/"
"TorFAQ#SOCKSAndDNS.%s", req->port,
safe_socks ? " Rejecting." : "");
// have_warned_about_unsafe_socks = 1; // (for now, warn every time)
control_event_client_status(LOG_WARN,
"DANGEROUS_SOCKS PROTOCOL=SOCKS5 ADDRESS=%s:%d",
req->address, req->port);
if (safe_socks)
return -1;
}
return 1;
case 3: /* fqdn */
log_debug(LD_APP,"socks5: fqdn address type");
if (req->command == SOCKS_COMMAND_RESOLVE_PTR) {
log_warn(LD_APP, "socks5 received RESOLVE_PTR command with "
"hostname type. Rejecting.");
return -1;
}
len = (unsigned char)*(buf->head->data+4);
if (buf->datalen < 7+len) /* addr/port there? */
return 0; /* not yet */
buf_pullup(buf, 7+len, 0);
tor_assert(buf->head->datalen >= 7+len);
if (len+1 > MAX_SOCKS_ADDR_LEN) {
log_warn(LD_APP,
"socks5 hostname is %d bytes, which doesn't fit in "
"%d. Rejecting.", len+1,MAX_SOCKS_ADDR_LEN);
return -1;
}
memcpy(req->address,buf->head->data+5,len);
req->address[len] = 0;
req->port = ntohs(get_uint16(buf->head->data+5+len));
buf_remove_from_front(buf, 5+len+2);
if (!tor_strisprint(req->address) || strchr(req->address,'\"')) {
log_warn(LD_PROTOCOL,
"Your application (using socks5 to port %d) gave Tor "
"a malformed hostname: %s. Rejecting the connection.",
req->port, escaped(req->address));
return -1;
}
if (log_sockstype)
log_notice(LD_APP,
"Your application (using socks5 to port %d) gave "
"Tor a hostname, which means Tor will do the DNS resolve "
"for you. This is good.", req->port);
return 1;
default: /* unsupported */
log_warn(LD_APP,"socks5: unsupported address type %d. Rejecting.",
(int) *(buf->head->data+3));
return -1;
}
tor_assert(0);
case 4: /* socks4 */
/* http://archive.socks.permeo.com/protocol/socks4.protocol */
/* http://archive.socks.permeo.com/protocol/socks4a.protocol */
req->socks_version = 4;
if (buf->datalen < SOCKS4_NETWORK_LEN) /* basic info available? */
return 0; /* not yet */
buf_pullup(buf, 1280, 0);
req->command = (unsigned char) *(buf->head->data+1);
if (req->command != SOCKS_COMMAND_CONNECT &&
req->command != SOCKS_COMMAND_RESOLVE) {
/* not a connect or resolve? we don't support it. (No resolve_ptr with
* socks4.) */
log_warn(LD_APP,"socks4: command %d not recognized. Rejecting.",
req->command);
return -1;
}
req->port = ntohs(*(uint16_t*)(buf->head->data+2));
destip = ntohl(*(uint32_t*)(buf->head->data+4));
if ((!req->port && req->command!=SOCKS_COMMAND_RESOLVE) || !destip) {
log_warn(LD_APP,"socks4: Port or DestIP is zero. Rejecting.");
return -1;
}
if (destip >> 8) {
log_debug(LD_APP,"socks4: destip not in form 0.0.0.x.");
in.s_addr = htonl(destip);
tor_inet_ntoa(&in,tmpbuf,sizeof(tmpbuf));
if (strlen(tmpbuf)+1 > MAX_SOCKS_ADDR_LEN) {
log_debug(LD_APP,"socks4 addr (%d bytes) too long. Rejecting.",
(int)strlen(tmpbuf));
return -1;
}
log_debug(LD_APP,
"socks4: successfully read destip (%s)", safe_str(tmpbuf));
socks4_prot = socks4;
}
next = memchr(buf->head->data+SOCKS4_NETWORK_LEN, 0,
buf->head->datalen-SOCKS4_NETWORK_LEN);
if (!next) {
if (buf->head->datalen >= 1024) {
log_debug(LD_APP, "Socks4 user name too long; rejecting.");
return -1;
}
log_debug(LD_APP,"socks4: Username not here yet.");
return 0;
}
tor_assert(next < CHUNK_WRITE_PTR(buf->head));
startaddr = NULL;
if (socks4_prot != socks4a &&
!addressmap_have_mapping(tmpbuf) &&
!have_warned_about_unsafe_socks) {
log_warn(LD_APP,
"Your application (using socks4 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 http://wiki.noreply.org/noreply/TheOnionRouter/"
"TorFAQ#SOCKSAndDNS.%s", req->port,
safe_socks ? " Rejecting." : "");
// have_warned_about_unsafe_socks = 1; // (for now, warn every time)
control_event_client_status(LOG_WARN,
"DANGEROUS_SOCKS PROTOCOL=SOCKS4 ADDRESS=%s:%d",
tmpbuf, req->port);
if (safe_socks)
return -1;
}
if (socks4_prot == socks4a) {
if (next+1 == CHUNK_WRITE_PTR(buf->head)) {
log_debug(LD_APP,"socks4: No part of destaddr here yet.");
return 0;
}
startaddr = next+1;
next = memchr(startaddr, 0, CHUNK_WRITE_PTR(buf->head)-startaddr);
if (!next) {
if (buf->head->datalen >= 1024) {
log_debug(LD_APP,"socks4: Destaddr too long.");
return -1;
}
log_debug(LD_APP,"socks4: Destaddr not all here yet.");
return 0;
}
if (MAX_SOCKS_ADDR_LEN <= next-startaddr) {
log_warn(LD_APP,"socks4: Destaddr too long. Rejecting.");
return -1;
}
// tor_assert(next < buf->cur+buf->datalen);
if (log_sockstype)
log_notice(LD_APP,
"Your application (using socks4a to port %d) gave "
"Tor a hostname, which means Tor will do the DNS resolve "
"for you. This is good.", req->port);
}
log_debug(LD_APP,"socks4: Everything is here. Success.");
strlcpy(req->address, startaddr ? startaddr : tmpbuf,
sizeof(req->address));
if (!tor_strisprint(req->address) || strchr(req->address,'\"')) {
log_warn(LD_PROTOCOL,
"Your application (using socks4 to port %d) gave Tor "
"a malformed hostname: %s. Rejecting the connection.",
req->port, escaped(req->address));
return -1;
}
/* next points to the final \0 on inbuf */
buf_remove_from_front(buf, next - buf->head->data + 1);
return 1;
case 'G': /* get */
case 'H': /* head */
case 'P': /* put/post */
case 'C': /* connect */
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 is a SOCKS proxy, not an HTTP proxy.\n"
"Please configure your client accordingly.\n"
"</p>\n"
"<p>\n"
"See <a href=\"https://www.torproject.org/documentation.html\">"
"https://www.torproject.org/documentation.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;
/* fall through */
default: /* version is not socks4 or socks5 */
log_warn(LD_APP,
"Socks version %d not recognized. (Tor is not an http proxy.)",
*(buf->head->data));
{
char *tmp = tor_strndup(buf->head->data, 8); /*XXXX what if longer?*/
control_event_client_status(LOG_WARN,
"SOCKS_UNKNOWN_PROTOCOL DATA=\"%s\"",
escaped(tmp));
tor_free(tmp);
}
return -1;
}
}
/** Return 1 iff buf looks more like it has an (obsolete) v0 controller
* command on it than any valid v1 controller command. */
int
peek_buf_has_control0_command(buf_t *buf)
{
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. */
}
return 0;
}
/** 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. */
static off_t
buf_find_offset_of_char(buf_t *buf, char ch)
{
chunk_t *chunk;
off_t offset = 0;
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;
}
/** Try to read a single LF-terminated line from <b>buf</b>, and write it,
* 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>.
*/
int
fetch_from_buf_line(buf_t *buf, char *data_out, size_t *data_len)
{
size_t sz;
off_t offset;
if (!buf->head)
return 0;
offset = buf_find_offset_of_char(buf, '\n');
if (offset < 0)
return 0;
sz = (size_t) offset;
if (sz+2 > *data_len) {
*data_len = sz + 2;
return -1;
}
fetch_from_buf(data_out, sz+1, buf);
data_out[sz+1] = '\0';
*data_len = sz+1;
return 1;
}
/** 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. */
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;
int over = 0;
do {
int need_new_chunk = 0;
if (!buf->tail || ! CHUNK_REMAINING_CAPACITY(buf->tail)) {
size_t cap = data_len / 4;
buf_add_chunk_with_capacity(buf, cap, 1);
}
next = CHUNK_WRITE_PTR(buf->tail);
avail = old_avail = CHUNK_REMAINING_CAPACITY(buf->tail);
switch (tor_zlib_process(state, &next, &avail, &data, &data_len, done)) {
case TOR_ZLIB_DONE:
over = 1;
break;
case TOR_ZLIB_ERR:
return -1;
case TOR_ZLIB_OK:
if (data_len == 0)
over = 1;
break;
case TOR_ZLIB_BUF_FULL:
if (avail) {
/* Zlib says we need more room (ZLIB_BUF_FULL). Start a new chunk
* automatically, whether were going to or not. */
need_new_chunk = 1;
}
break;
}
buf->datalen += old_avail - avail;
buf->tail->datalen += old_avail - avail;
if (need_new_chunk) {
buf_add_chunk_with_capacity(buf, data_len/4, 1);
}
} while (!over);
check();
return 0;
}
/** Log an error and exit if <b>buf</b> is corrupted.
*/
void
assert_buf_ok(buf_t *buf)
{
tor_assert(buf);
tor_assert(buf->magic == BUFFER_MAGIC);
if (! buf->head) {
tor_assert(!buf->tail);
tor_assert(buf->datalen == 0);
} else {
chunk_t *ch;
size_t total = 0;
tor_assert(buf->tail);
for (ch = buf->head; ch; ch = ch->next) {
total += ch->datalen;
tor_assert(ch->datalen <= ch->memlen);
tor_assert(ch->data >= &ch->mem[0]);
tor_assert(ch->data < &ch->mem[0]+ch->memlen);
tor_assert(ch->data+ch->datalen <= &ch->mem[0] + ch->memlen);
if (!ch->next)
tor_assert(ch == buf->tail);
}
tor_assert(buf->datalen == total);
}
}
#ifdef ENABLE_BUF_FREELISTS
/** Log an error and exit if <b>fl</b> is corrupted.
*/
static void
assert_freelist_ok(chunk_freelist_t *fl)
{
chunk_t *ch;
int n;
tor_assert(fl->alloc_size > 0);
n = 0;
for (ch = fl->head; ch; ch = ch->next) {
tor_assert(CHUNK_ALLOC_SIZE(ch->memlen) == fl->alloc_size);
++n;
}
tor_assert(n == fl->cur_length);
tor_assert(n >= fl->lowest_length);
tor_assert(n <= fl->max_length);
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -