Commit a6a45b77 authored by Nick Mathewson's avatar Nick Mathewson 🎨
Browse files

Add TTLs to RESOLVED, CONNECTED, and END_REASON_EXITPOLICY cells. Also, add a...

Add TTLs to RESOLVED, CONNECTED, and END_REASON_EXITPOLICY cells.  Also, add a missing ntohl in connection_ap_handshake_socks_resolved.


svn:r4894
parent 93179f4e
...@@ -469,8 +469,16 @@ TODO: (very soon) ...@@ -469,8 +469,16 @@ TODO: (very soon)
address cannot be resolved, or a connection can't be established, the address cannot be resolved, or a connection can't be established, the
exit node replies with a RELAY_END cell. (See 5.4 below.) exit node replies with a RELAY_END cell. (See 5.4 below.)
Otherwise, the exit node replies with a RELAY_CONNECTED cell, whose Otherwise, the exit node replies with a RELAY_CONNECTED cell, whose
payload is the 4-byte IPv4 address or the 16-byte IPv6 address to which payload is in one of the following formats:
the connection was made. The IPv4 address to which the connection was made [4 octets]
A number of seconds (TTL) for which the address may be cached [4 octets]
or
Four zero-valued octets [4 octets]
An address type (6) [1 octet]
The IPv6 address to which the connection was made [16 octets]
A number of seconds (TTL) for which the address may be cached [4 octets]
[XXXX Versions of Tor before 0.1.1.6 ignore and do not generate the TTL
field. No version of Tor currently generates the IPv6 format.]
The OP waits for a RELAY_CONNECTED cell before sending any data. The OP waits for a RELAY_CONNECTED cell before sending any data.
Once a connection has been established, the OP and exit node Once a connection has been established, the OP and exit node
...@@ -511,7 +519,8 @@ TODO: (very soon) ...@@ -511,7 +519,8 @@ TODO: (very soon)
Tor protocol violations.) Tor protocol violations.)
(With REASON_EXITPOLICY, the 4-byte IPv4 address or 16-byte IPv6 address (With REASON_EXITPOLICY, the 4-byte IPv4 address or 16-byte IPv6 address
forms the optional data; no other reason currently has extra data.) forms the optional data; no other reason currently has extra data.
As of 0.1.1.6, the body also contains a 4-byte TTL.)
OPs and ORs MUST accept reasons not on the above list, since future OPs and ORs MUST accept reasons not on the above list, since future
versions of Tor may provide more fine-grained reasons. versions of Tor may provide more fine-grained reasons.
...@@ -558,6 +567,7 @@ TODO: (very soon) ...@@ -558,6 +567,7 @@ TODO: (very soon)
Type (1 octet) Type (1 octet)
Length (1 octet) Length (1 octet)
Value (variable-width) Value (variable-width)
TTL (4 octets)
"Length" is the length of the Value field. "Length" is the length of the Value field.
"Type" is one of: "Type" is one of:
0x00 -- Hostname 0x00 -- Hostname
......
...@@ -48,7 +48,7 @@ _connection_mark_unattached_ap(connection_t *conn, int endreason, ...@@ -48,7 +48,7 @@ _connection_mark_unattached_ap(connection_t *conn, int endreason,
if (conn->socks_request->command == SOCKS_COMMAND_CONNECT) if (conn->socks_request->command == SOCKS_COMMAND_CONNECT)
connection_ap_handshake_socks_reply(conn, NULL, 0, socksreason); connection_ap_handshake_socks_reply(conn, NULL, 0, socksreason);
else else
connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_ERROR,0,NULL); connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_ERROR,0,NULL,-1);
} }
_connection_mark_for_close(conn, line, file); _connection_mark_for_close(conn, line, file);
...@@ -194,7 +194,8 @@ connection_edge_end(connection_t *conn, char reason, crypt_path_t *cpath_layer) ...@@ -194,7 +194,8 @@ connection_edge_end(connection_t *conn, char reason, crypt_path_t *cpath_layer)
/* this is safe even for rend circs, because they never fail /* this is safe even for rend circs, because they never fail
* because of exitpolicy */ * because of exitpolicy */
set_uint32(payload+1, htonl(conn->addr)); set_uint32(payload+1, htonl(conn->addr));
payload_len += 4; set_uint32(payload+5, htonl(MAX_DNS_ENTRY_AGE)); /* XXXXfill with a real TTL*/
payload_len += 8;
} }
circ = circuit_get_by_edge_conn(conn); circ = circuit_get_by_edge_conn(conn);
...@@ -266,7 +267,6 @@ connection_edge_finished_flushing(connection_t *conn) ...@@ -266,7 +267,6 @@ connection_edge_finished_flushing(connection_t *conn)
int int
connection_edge_finished_connecting(connection_t *conn) connection_edge_finished_connecting(connection_t *conn)
{ {
char connected_payload[4];
char valbuf[INET_NTOA_BUF_LEN]; char valbuf[INET_NTOA_BUF_LEN];
struct in_addr in; struct in_addr in;
...@@ -289,9 +289,12 @@ connection_edge_finished_connecting(connection_t *conn) ...@@ -289,9 +289,12 @@ connection_edge_finished_connecting(connection_t *conn)
RELAY_COMMAND_CONNECTED, NULL, 0, conn->cpath_layer) < 0) RELAY_COMMAND_CONNECTED, NULL, 0, conn->cpath_layer) < 0)
return 0; /* circuit is closed, don't continue */ return 0; /* circuit is closed, don't continue */
} else { } else {
*(uint32_t*)connected_payload = htonl(conn->addr); char connected_payload[8];
set_uint32(connected_payload, htonl(htonl(conn->addr)));
set_uint32(connected_payload+4,
htonl(MAX_DNS_ENTRY_AGE)); /* XXXX fill with a real TTL */
if (connection_edge_send_command(conn, circuit_get_by_edge_conn(conn), if (connection_edge_send_command(conn, circuit_get_by_edge_conn(conn),
RELAY_COMMAND_CONNECTED, connected_payload, 4, conn->cpath_layer) < 0) RELAY_COMMAND_CONNECTED, connected_payload, 8, conn->cpath_layer) < 0)
return 0; /* circuit is closed, don't continue */ return 0; /* circuit is closed, don't continue */
} }
tor_assert(conn->package_window > 0); tor_assert(conn->package_window > 0);
...@@ -683,9 +686,13 @@ client_dns_clear_failures(const char *address) ...@@ -683,9 +686,13 @@ client_dns_clear_failures(const char *address)
* *
* If <b>exitname</b> is defined, then append the addresses with * If <b>exitname</b> is defined, then append the addresses with
* ".exitname.exit" before registering the mapping. * ".exitname.exit" before registering the mapping.
*
* If <b>ttl</b> is nonnegative, the mapping will be valid for
* <b>ttl</b>seconds.
*/ */
void void
client_dns_set_addressmap(const char *address, uint32_t val, const char *exitname) client_dns_set_addressmap(const char *address, uint32_t val, const char *exitname,
int ttl)
{ {
struct in_addr in; struct in_addr in;
char extendedaddress[MAX_SOCKS_ADDR_LEN+MAX_HEX_NICKNAME_LEN+10]; char extendedaddress[MAX_SOCKS_ADDR_LEN+MAX_HEX_NICKNAME_LEN+10];
...@@ -694,6 +701,9 @@ client_dns_set_addressmap(const char *address, uint32_t val, const char *exitnam ...@@ -694,6 +701,9 @@ client_dns_set_addressmap(const char *address, uint32_t val, const char *exitnam
tor_assert(address); tor_assert(val); tor_assert(address); tor_assert(val);
if (ttl<0 || ttl>MAX_DNS_ENTRY_AGE)
ttl = MAX_DNS_ENTRY_AGE;
if (tor_inet_aton(address, &in)) if (tor_inet_aton(address, &in))
return; /* If address was an IP address already, don't add a mapping. */ return; /* If address was an IP address already, don't add a mapping. */
in.s_addr = htonl(val); in.s_addr = htonl(val);
...@@ -709,8 +719,7 @@ client_dns_set_addressmap(const char *address, uint32_t val, const char *exitnam ...@@ -709,8 +719,7 @@ client_dns_set_addressmap(const char *address, uint32_t val, const char *exitnam
tor_snprintf(extendedval, sizeof(extendedval), tor_snprintf(extendedval, sizeof(extendedval),
"%s", valbuf); "%s", valbuf);
} }
addressmap_register(extendedaddress, tor_strdup(extendedval), addressmap_register(extendedaddress, tor_strdup(extendedval), time(NULL) + ttl);
time(NULL) + MAX_DNS_ENTRY_AGE);
} }
/* Currently, we hand out 127.192.0.1 through 127.254.254.254. /* Currently, we hand out 127.192.0.1 through 127.254.254.254.
...@@ -1019,14 +1028,14 @@ connection_ap_handshake_process_socks(connection_t *conn) ...@@ -1019,14 +1028,14 @@ connection_ap_handshake_process_socks(connection_t *conn)
/* Reply to resolves immediately if we can. */ /* Reply to resolves immediately if we can. */
if (strlen(socks->address) > RELAY_PAYLOAD_SIZE) { if (strlen(socks->address) > RELAY_PAYLOAD_SIZE) {
log_fn(LOG_WARN,"Address to be resolved is too large. Failing."); log_fn(LOG_WARN,"Address to be resolved is too large. Failing.");
connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_ERROR,0,NULL); connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_ERROR,0,NULL,-1);
connection_mark_unattached_ap(conn, END_STREAM_REASON_ALREADY_SOCKS_REPLIED); connection_mark_unattached_ap(conn, END_STREAM_REASON_ALREADY_SOCKS_REPLIED);
return -1; return -1;
} }
if (tor_inet_aton(socks->address, &in)) { /* see if it's an IP already */ if (tor_inet_aton(socks->address, &in)) { /* see if it's an IP already */
answer = in.s_addr; /* leave it in network order */ answer = in.s_addr; /* leave it in network order */
connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_IPV4,4, connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_IPV4,4,
(char*)&answer); (char*)&answer,-1);
connection_mark_unattached_ap(conn, END_STREAM_REASON_ALREADY_SOCKS_REPLIED); connection_mark_unattached_ap(conn, END_STREAM_REASON_ALREADY_SOCKS_REPLIED);
return 0; return 0;
} }
...@@ -1075,7 +1084,7 @@ connection_ap_handshake_process_socks(connection_t *conn) ...@@ -1075,7 +1084,7 @@ connection_ap_handshake_process_socks(connection_t *conn)
/* if it's a resolve request, fail it right now, rather than /* if it's a resolve request, fail it right now, rather than
* building all the circuits and then realizing it won't work. */ * building all the circuits and then realizing it won't work. */
log_fn(LOG_WARN,"Resolve requests to hidden services not allowed. Failing."); log_fn(LOG_WARN,"Resolve requests to hidden services not allowed. Failing.");
connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_ERROR,0,NULL); connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_ERROR,0,NULL,-1);
connection_mark_unattached_ap(conn, END_STREAM_REASON_ALREADY_SOCKS_REPLIED); connection_mark_unattached_ap(conn, END_STREAM_REASON_ALREADY_SOCKS_REPLIED);
return -1; return -1;
} }
...@@ -1299,16 +1308,17 @@ void ...@@ -1299,16 +1308,17 @@ void
connection_ap_handshake_socks_resolved(connection_t *conn, connection_ap_handshake_socks_resolved(connection_t *conn,
int answer_type, int answer_type,
size_t answer_len, size_t answer_len,
const char *answer) const char *answer,
int ttl)
{ {
char buf[256]; char buf[256];
size_t replylen; size_t replylen;
if (answer_type == RESOLVED_TYPE_IPV4) { if (answer_type == RESOLVED_TYPE_IPV4) {
uint32_t a = get_uint32(answer); uint32_t a = ntohl(get_uint32(answer));
if (a) if (a)
client_dns_set_addressmap(conn->socks_request->address, ntohl(a), client_dns_set_addressmap(conn->socks_request->address, ntohl(a),
conn->chosen_exit_name); conn->chosen_exit_name, ttl);
} }
if (conn->socks_request->socks_version == 4) { if (conn->socks_request->socks_version == 4) {
...@@ -1581,7 +1591,6 @@ connection_exit_begin_resolve(cell_t *cell, circuit_t *circ) ...@@ -1581,7 +1591,6 @@ connection_exit_begin_resolve(cell_t *cell, circuit_t *circ)
void void
connection_exit_connect(connection_t *conn) connection_exit_connect(connection_t *conn)
{ {
char connected_payload[4];
uint32_t addr; uint32_t addr;
uint16_t port; uint16_t port;
...@@ -1649,10 +1658,13 @@ connection_exit_connect(connection_t *conn) ...@@ -1649,10 +1658,13 @@ connection_exit_connect(connection_t *conn)
NULL, 0, conn->cpath_layer); NULL, 0, conn->cpath_layer);
} else { /* normal stream */ } else { /* normal stream */
/* This must be the original address, not the redirected address. */ /* This must be the original address, not the redirected address. */
*(uint32_t*)connected_payload = htonl(conn->addr); char connected_payload[8];
set_uint32(connected_payload, htonl(htonl(conn->addr)));
set_uint32(connected_payload+4,
htonl(MAX_DNS_ENTRY_AGE)); /* XXXX fill with a real TTL */
connection_edge_send_command(conn, circuit_get_by_edge_conn(conn), connection_edge_send_command(conn, circuit_get_by_edge_conn(conn),
RELAY_COMMAND_CONNECTED, RELAY_COMMAND_CONNECTED,
connected_payload, 4, conn->cpath_layer); connected_payload, 8, conn->cpath_layer);
} }
} }
......
...@@ -192,14 +192,21 @@ send_resolved_cell(connection_t *conn, uint8_t answer_type) ...@@ -192,14 +192,21 @@ send_resolved_cell(connection_t *conn, uint8_t answer_type)
case RESOLVED_TYPE_IPV4: case RESOLVED_TYPE_IPV4:
buf[1] = 4; buf[1] = 4;
set_uint32(buf+2, htonl(conn->addr)); set_uint32(buf+2, htonl(conn->addr));
buflen = 6; set_uint32(buf+6, htonl(MAX_DNS_ENTRY_AGE)); /*XXXX send a real TTL*/
buflen = 10;
break; break;
case RESOLVED_TYPE_ERROR_TRANSIENT: case RESOLVED_TYPE_ERROR_TRANSIENT:
case RESOLVED_TYPE_ERROR: case RESOLVED_TYPE_ERROR:
buf[1] = 24; /* length of "error resolving hostname" */ {
strlcpy(buf+2, "error resolving hostname", sizeof(buf)-2); const char *errmsg = "Error resolving hostname";
buflen = 26; int msglen = strlen(errmsg);
int ttl = (answer_type == RESOLVED_TYPE_ERROR ? MAX_DNS_ENTRY_AGE : 0);
buf[1] = msglen;
strlcpy(buf+2, errmsg, sizeof(buf)-2);
set_uint32(buf+2+msglen, htonl((uint32_t)ttl));
buflen = 6+msglen;
break; break;
}
default: default:
tor_assert(0); tor_assert(0);
} }
......
...@@ -640,14 +640,19 @@ connection_edge_process_end_not_open( ...@@ -640,14 +640,19 @@ connection_edge_process_end_not_open(
case END_STREAM_REASON_EXITPOLICY: case END_STREAM_REASON_EXITPOLICY:
if (rh->length >= 5) { if (rh->length >= 5) {
uint32_t addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+1)); uint32_t addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+1));
int ttl;
if (!addr) { if (!addr) {
log_fn(LOG_INFO,"Address '%s' resolved to 0.0.0.0. Closing,", log_fn(LOG_INFO,"Address '%s' resolved to 0.0.0.0. Closing,",
safe_str(conn->socks_request->address)); safe_str(conn->socks_request->address));
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
return 0; return 0;
} }
if (rh->length >= 9)
ttl = (int)ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+5));
else
ttl = -1;
client_dns_set_addressmap(conn->socks_request->address, addr, client_dns_set_addressmap(conn->socks_request->address, addr,
conn->chosen_exit_name); conn->chosen_exit_name, ttl);
} }
/* check if he *ought* to have allowed it */ /* check if he *ought* to have allowed it */
if (exitrouter && if (exitrouter &&
...@@ -735,14 +740,19 @@ connection_edge_process_relay_cell_not_open( ...@@ -735,14 +740,19 @@ connection_edge_process_relay_cell_not_open(
(int)(time(NULL) - conn->timestamp_lastread)); (int)(time(NULL) - conn->timestamp_lastread));
if (rh->length >= 4) { if (rh->length >= 4) {
uint32_t addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE)); uint32_t addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE));
int ttl;
if (!addr) { if (!addr) {
log_fn(LOG_INFO,"...but it claims the IP address was 0.0.0.0. Closing."); log_fn(LOG_INFO,"...but it claims the IP address was 0.0.0.0. Closing.");
connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL, conn->cpath_layer); connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL, conn->cpath_layer);
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
return 0; return 0;
} }
if (rh->length >= 8)
ttl = (int)ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+8));
else
ttl = -1;
client_dns_set_addressmap(conn->socks_request->address, addr, client_dns_set_addressmap(conn->socks_request->address, addr,
conn->chosen_exit_name); conn->chosen_exit_name, ttl);
} }
circuit_log_path(LOG_INFO,circ); circuit_log_path(LOG_INFO,circ);
connection_ap_handshake_socks_reply(conn, NULL, 0, SOCKS5_SUCCEEDED); connection_ap_handshake_socks_reply(conn, NULL, 0, SOCKS5_SUCCEEDED);
...@@ -755,20 +765,28 @@ connection_edge_process_relay_cell_not_open( ...@@ -755,20 +765,28 @@ connection_edge_process_relay_cell_not_open(
return 0; return 0;
} }
if (conn->type == CONN_TYPE_AP && rh->command == RELAY_COMMAND_RESOLVED) { if (conn->type == CONN_TYPE_AP && rh->command == RELAY_COMMAND_RESOLVED) {
int ttl;
int answer_len;
if (conn->state != AP_CONN_STATE_RESOLVE_WAIT) { if (conn->state != AP_CONN_STATE_RESOLVE_WAIT) {
log_fn(LOG_WARN,"Got a 'resolved' cell while not in state resolve_wait. Dropping."); log_fn(LOG_WARN,"Got a 'resolved' cell while not in state resolve_wait. Dropping.");
return 0; return 0;
} }
tor_assert(conn->socks_request->command == SOCKS_COMMAND_RESOLVE); tor_assert(conn->socks_request->command == SOCKS_COMMAND_RESOLVE);
if (rh->length < 2 || cell->payload[RELAY_HEADER_SIZE+1]+2>rh->length) { answer_len = cell->payload[RELAY_HEADER_SIZE+1];
if (rh->length < 2 || answer_len+2>rh->length) {
log_fn(LOG_WARN, "Dropping malformed 'resolved' cell"); log_fn(LOG_WARN, "Dropping malformed 'resolved' cell");
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
return 0; return 0;
} }
if (rh->length >= answer_len+6)
ttl = (int)ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+6));
else
ttl = -1;
connection_ap_handshake_socks_resolved(conn, connection_ap_handshake_socks_resolved(conn,
cell->payload[RELAY_HEADER_SIZE], /*answer_type*/ cell->payload[RELAY_HEADER_SIZE], /*answer_type*/
cell->payload[RELAY_HEADER_SIZE+1], /*answer_len*/ cell->payload[RELAY_HEADER_SIZE+1], /*answer_len*/
cell->payload+RELAY_HEADER_SIZE+2); /* answer */ cell->payload+RELAY_HEADER_SIZE+2,
ttl); /* answer */
connection_mark_unattached_ap(conn, END_STREAM_REASON_ALREADY_SOCKS_REPLIED); connection_mark_unattached_ap(conn, END_STREAM_REASON_ALREADY_SOCKS_REPLIED);
return 0; return 0;
} }
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment