📄 connection_edge.c
字号:
if (s[1] != '\0') {
conn->chosen_exit_name = tor_strdup(s+1);
/* DOCDOC */
#define TRACKHOSTEXITS_RETRIES 5
if (remapped_to_exit) /* 5 tries before it expires the addressmap */
TO_CONN(conn)->chosen_exit_retries = TRACKHOSTEXITS_RETRIES;
*s = 0;
} else {
log_warn(LD_APP,"Malformed exit address '%s.exit'. Refusing.",
safe_str(socks->address));
control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s",
escaped(socks->address));
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
return -1;
}
} else {
routerinfo_t *r;
conn->chosen_exit_name = tor_strdup(socks->address);
r = router_get_by_nickname(conn->chosen_exit_name, 1);
*socks->address = 0;
if (r) {
strlcpy(socks->address, r->address, sizeof(socks->address));
} else {
log_warn(LD_APP,
"Unrecognized server in exit address '%s.exit'. Refusing.",
safe_str(socks->address));
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
return -1;
}
}
}
if (addresstype != ONION_HOSTNAME) {
/* not a hidden-service request (i.e. normal or .exit) */
if (address_is_invalid_destination(socks->address, 1)) {
control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s",
escaped(socks->address));
log_warn(LD_APP,
"Destination '%s' seems to be an invalid hostname. Failing.",
safe_str(socks->address));
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
return -1;
}
if (socks->command == SOCKS_COMMAND_RESOLVE) {
uint32_t answer;
struct in_addr in;
/* Reply to resolves immediately if we can. */
if (strlen(socks->address) > RELAY_PAYLOAD_SIZE) {
log_warn(LD_APP,"Address to be resolved is too large. Failing.");
control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s",
escaped(socks->address));
connection_ap_handshake_socks_resolved(conn,
RESOLVED_TYPE_ERROR_TRANSIENT,
0,NULL,-1,TIME_MAX);
connection_mark_unattached_ap(conn,
END_STREAM_REASON_SOCKSPROTOCOL |
END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
return -1;
}
if (tor_inet_aton(socks->address, &in)) { /* see if it's an IP already */
/* leave it in network order */
answer = in.s_addr;
/* remember _what_ is supposed to have been resolved. */
strlcpy(socks->address, orig_address, sizeof(socks->address));
connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_IPV4,4,
(char*)&answer,-1,map_expires);
connection_mark_unattached_ap(conn,
END_STREAM_REASON_DONE |
END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
return 0;
}
tor_assert(!automap);
rep_hist_note_used_resolve(now); /* help predict this next time */
} else if (socks->command == SOCKS_COMMAND_CONNECT) {
tor_assert(!automap);
if (socks->port == 0) {
log_notice(LD_APP,"Application asked to connect to port 0. Refusing.");
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
return -1;
}
if (!conn->use_begindir && !conn->chosen_exit_name && !circ) {
/* see if we can find a suitable enclave exit */
routerinfo_t *r =
router_find_exact_exit_enclave(socks->address, socks->port);
if (r) {
log_info(LD_APP,
"Redirecting address %s to exit at enclave router %s",
safe_str(socks->address), r->nickname);
/* use the hex digest, not nickname, in case there are two
routers with this nickname */
conn->chosen_exit_name =
tor_strdup(hex_str(r->cache_info.identity_digest, DIGEST_LEN));
conn->_base.chosen_exit_optional = 1;
}
}
/* warn or reject if it's using a dangerous port */
if (!conn->use_begindir && !conn->chosen_exit_name && !circ)
if (consider_plaintext_ports(conn, socks->port) < 0)
return -1;
if (!conn->use_begindir) {
/* help predict this next time */
rep_hist_note_used_port(now, socks->port);
}
} else if (socks->command == SOCKS_COMMAND_RESOLVE_PTR) {
rep_hist_note_used_resolve(now); /* help predict this next time */
/* no extra processing needed */
} else {
tor_fragile_assert();
}
conn->_base.state = AP_CONN_STATE_CIRCUIT_WAIT;
if ((circ && connection_ap_handshake_attach_chosen_circuit(
conn, circ, cpath) < 0) ||
(!circ &&
connection_ap_handshake_attach_circuit(conn) < 0)) {
if (!conn->_base.marked_for_close)
connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH);
return -1;
}
return 0;
} else {
/* it's a hidden-service request */
rend_cache_entry_t *entry;
int r;
tor_assert(!automap);
if (SOCKS_COMMAND_IS_RESOLVE(socks->command)) {
/* if it's a resolve request, fail it right now, rather than
* building all the circuits and then realizing it won't work. */
log_warn(LD_APP,
"Resolve requests to hidden services not allowed. Failing.");
connection_ap_handshake_socks_resolved(conn,RESOLVED_TYPE_ERROR,
0,NULL,-1,TIME_MAX);
connection_mark_unattached_ap(conn,
END_STREAM_REASON_SOCKSPROTOCOL |
END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
return -1;
}
if (circ) {
log_warn(LD_CONTROL, "Attachstream to a circuit is not "
"supported for .onion addresses currently. Failing.");
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
return -1;
}
strlcpy(conn->rend_query, socks->address, sizeof(conn->rend_query));
log_info(LD_REND,"Got a hidden service request for ID '%s'",
safe_str(conn->rend_query));
/* see if we already have it cached */
r = rend_cache_lookup_entry(conn->rend_query, -1, &entry);
if (r<0) {
log_warn(LD_BUG,"Invalid service name '%s'",
safe_str(conn->rend_query));
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
return -1;
}
/* Help predict this next time. We're not sure if it will need
* a stable circuit yet, but we know we'll need *something*. */
rep_hist_note_used_internal(now, 0, 1);
if (r==0) {
conn->_base.state = AP_CONN_STATE_RENDDESC_WAIT;
log_info(LD_REND, "Unknown descriptor %s. Fetching.",
safe_str(conn->rend_query));
/* Fetch both, v0 and v2 rend descriptors in parallel. Use whichever
* arrives first. */
rend_client_refetch_v2_renddesc(conn->rend_query);
rend_client_refetch_renddesc(conn->rend_query);
} else { /* r > 0 */
/** How long after we receive a hidden service descriptor do we consider
* it valid? */
#define NUM_SECONDS_BEFORE_HS_REFETCH (60*15)
if (now - entry->received < NUM_SECONDS_BEFORE_HS_REFETCH) {
conn->_base.state = AP_CONN_STATE_CIRCUIT_WAIT;
log_info(LD_REND, "Descriptor is here and fresh enough. Great.");
if (connection_ap_handshake_attach_circuit(conn) < 0) {
if (!conn->_base.marked_for_close)
connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH);
return -1;
}
} else {
conn->_base.state = AP_CONN_STATE_RENDDESC_WAIT;
log_info(LD_REND, "Stale descriptor %s. Refetching.",
safe_str(conn->rend_query));
/* Fetch both, v0 and v2 rend descriptors in parallel. Use whichever
* arrives first. */
rend_client_refetch_v2_renddesc(conn->rend_query);
rend_client_refetch_renddesc(conn->rend_query);
}
}
return 0;
}
return 0; /* unreached but keeps the compiler happy */
}
#ifdef TRANS_PF
static int pf_socket = -1;
static int
get_pf_socket(void)
{
int pf;
/* Ideally, this should be opened before dropping privs. */
if (pf_socket >= 0)
return pf_socket;
#ifdef OPENBSD
/* only works on OpenBSD */
pf = open("/dev/pf", O_RDONLY);
#else
/* works on NetBSD and FreeBSD */
pf = open("/dev/pf", O_RDWR);
#endif
if (pf < 0) {
log_warn(LD_NET, "open(\"/dev/pf\") failed: %s", strerror(errno));
return -1;
}
pf_socket = pf;
return pf_socket;
}
#endif
/** Fetch the original destination address and port from a
* system-specific interface and put them into a
* socks_request_t as if they came from a socks request.
*
* Return -1 if an error prevents fetching the destination,
* else return 0.
*/
static int
connection_ap_get_original_destination(edge_connection_t *conn,
socks_request_t *req)
{
#ifdef TRANS_NETFILTER
/* Linux 2.4+ */
struct sockaddr_in orig_dst;
socklen_t orig_dst_len = sizeof(orig_dst);
char tmpbuf[INET_NTOA_BUF_LEN];
if (getsockopt(conn->_base.s, SOL_IP, SO_ORIGINAL_DST,
(struct sockaddr*)&orig_dst, &orig_dst_len) < 0) {
int e = tor_socket_errno(conn->_base.s);
log_warn(LD_NET, "getsockopt() failed: %s", tor_socket_strerror(e));
return -1;
}
tor_inet_ntoa(&orig_dst.sin_addr, tmpbuf, sizeof(tmpbuf));
strlcpy(req->address, tmpbuf, sizeof(req->address));
req->port = ntohs(orig_dst.sin_port);
return 0;
#elif defined(TRANS_PF)
struct sockaddr_in proxy_addr;
socklen_t proxy_addr_len = sizeof(proxy_addr);
char tmpbuf[INET_NTOA_BUF_LEN];
struct pfioc_natlook pnl;
int pf = -1;
if (getsockname(conn->_base.s, (struct sockaddr*)&proxy_addr,
&proxy_addr_len) < 0) {
int e = tor_socket_errno(conn->_base.s);
log_warn(LD_NET, "getsockname() to determine transocks destination "
"failed: %s", tor_socket_strerror(e));
return -1;
}
memset(&pnl, 0, sizeof(pnl));
pnl.af = AF_INET;
pnl.proto = IPPROTO_TCP;
pnl.direction = PF_OUT;
pnl.saddr.v4.s_addr = htonl(conn->_base.addr);
pnl.sport = htons(conn->_base.port);
pnl.daddr.v4.s_addr = proxy_addr.sin_addr.s_addr;
pnl.dport = proxy_addr.sin_port;
pf = get_pf_socket();
if (pf<0)
return -1;
if (ioctl(pf, DIOCNATLOOK, &pnl) < 0) {
log_warn(LD_NET, "ioctl(DIOCNATLOOK) failed: %s", strerror(errno));
return -1;
}
tor_inet_ntoa(&pnl.rdaddr.v4, tmpbuf, sizeof(tmpbuf));
strlcpy(req->address, tmpbuf, sizeof(req->address));
req->port = ntohs(pnl.rdport);
return 0;
#else
(void)conn;
(void)req;
log_warn(LD_BUG, "Called connection_ap_get_original_destination, but no "
"transparent proxy method was configured.");
return -1;
#endif
}
/** connection_edge_process_inbuf() found a conn in state
* socks_wait. See if conn->inbuf has the right bytes to proceed with
* the socks handshake.
*
* If the handshake is complete, send it to
* connection_ap_handshake_rewrite_and_attach().
*
* Return -1 if an unexpected error with conn occurs (and mark it for close),
* else return 0.
*/
static int
connection_ap_handshake_process_socks(edge_connection_t *conn)
{
socks_request_t *socks;
int sockshere;
or_options_t *options = get_options();
tor_assert(conn);
tor_assert(conn->_base.type == CONN_TYPE_AP);
tor_assert(conn->_base.state == AP_CONN_STATE_SOCKS_WAIT);
tor_assert(conn->socks_request);
socks = conn->socks_request;
log_debug(LD_APP,"entered.");
sockshere = fetch_from_buf_socks(conn->_base.inbuf, socks,
options->TestSocks, options->SafeSocks);
if (sockshere == 0) {
if (socks->replylen) {
connection_write_to_buf(socks->reply, socks->replylen, TO_CONN(conn));
/* zero it out so we can do another round of negotiation */
socks->replylen = 0;
} else {
log_debug(LD_APP,"socks handshake not all here yet.");
}
return 0;
} else if (sockshere == -1) {
if (socks->replylen) { /* we should send reply back */
log_debug(LD_APP,"reply is already set for us. Using it.");
connection_ap_handshake_socks_reply(conn, socks->reply, socks->replylen,
END_STREAM_REASON_SOCKSPROTOCOL);
} else {
log_warn(LD_APP,"Fetching socks handshake failed. Closing.");
connection_ap_handshake_socks_reply(conn, NULL, 0,
END_STREAM_REASON_SOCKSPROTOCOL);
}
connection_mark_unattached_ap(conn,
END_STREAM_REASON_SOCKSPROTOCOL |
END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
return -1;
} /* else socks handshake is done, continue processing */
if (hostname_is_noconnect_address(socks->addr
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -