/src/tor/src/feature/rend/rendmid.c
Line | Count | Source |
1 | | /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. |
2 | | * Copyright (c) 2007-2021, The Tor Project, Inc. */ |
3 | | /* See LICENSE for licensing information */ |
4 | | |
5 | | /** |
6 | | * \file rendmid.c |
7 | | * \brief Implement introductions points and rendezvous points. |
8 | | **/ |
9 | | |
10 | | #include "core/or/or.h" |
11 | | #include "core/or/channel.h" |
12 | | #include "core/or/circuitlist.h" |
13 | | #include "core/or/circuituse.h" |
14 | | #include "app/config/config.h" |
15 | | #include "lib/crypt_ops/crypto_cipher.h" |
16 | | #include "core/or/dos.h" |
17 | | #include "core/or/relay.h" |
18 | | #include "feature/rend/rendmid.h" |
19 | | #include "feature/hs/hs_circuitmap.h" |
20 | | #include "feature/hs/hs_dos.h" |
21 | | #include "feature/hs/hs_intropoint.h" |
22 | | #include "feature/relay/relay_metrics.h" |
23 | | |
24 | | #include "core/or/or_circuit_st.h" |
25 | | |
26 | | /** Process an ESTABLISH_RENDEZVOUS cell by setting the circuit's purpose and |
27 | | * rendezvous cookie. |
28 | | */ |
29 | | int |
30 | | rend_mid_establish_rendezvous(or_circuit_t *circ, const uint8_t *request, |
31 | | size_t request_len) |
32 | 0 | { |
33 | 0 | char hexid[9]; |
34 | 0 | int reason = END_CIRC_REASON_TORPROTOCOL; |
35 | |
|
36 | 0 | log_info(LD_REND, "Received an ESTABLISH_RENDEZVOUS request on circuit %u", |
37 | 0 | (unsigned)circ->p_circ_id); |
38 | |
|
39 | 0 | if (circ->base_.purpose != CIRCUIT_PURPOSE_OR) { |
40 | 0 | relay_increment_est_rend_action(EST_REND_UNSUITABLE_CIRCUIT); |
41 | 0 | log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, |
42 | 0 | "Tried to establish rendezvous on non-OR circuit with purpose %s", |
43 | 0 | circuit_purpose_to_string(circ->base_.purpose)); |
44 | 0 | goto err; |
45 | 0 | } |
46 | | |
47 | | /* Check if we are configured to defend ourselves from clients that |
48 | | * attempt to establish rendezvous points directly to us. */ |
49 | 0 | if (channel_is_client(circ->p_chan) && |
50 | 0 | dos_should_refuse_single_hop_client()) { |
51 | 0 | relay_increment_est_rend_action(EST_REND_SINGLE_HOP); |
52 | | /* Note it down for the heartbeat log purposes. */ |
53 | 0 | dos_note_refuse_single_hop_client(); |
54 | | /* Silent drop so the client has to time out before moving on. */ |
55 | 0 | return 0; |
56 | 0 | } |
57 | | |
58 | 0 | if (circ->base_.n_chan) { |
59 | 0 | relay_increment_est_rend_action(EST_REND_UNSUITABLE_CIRCUIT); |
60 | 0 | log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, |
61 | 0 | "Tried to establish rendezvous on non-edge circuit"); |
62 | 0 | goto err; |
63 | 0 | } |
64 | | |
65 | | /* A (pending) conflux leg must stay a plain OR circuit: changing its |
66 | | * purpose is treated as a close of the leg by the conflux subsystem. */ |
67 | 0 | if (circ->base_.conflux || circ->base_.conflux_pending_nonce) { |
68 | 0 | relay_increment_est_rend_action(EST_REND_UNSUITABLE_CIRCUIT); |
69 | 0 | log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, |
70 | 0 | "Tried to establish rendezvous on a conflux circuit"); |
71 | 0 | goto err; |
72 | 0 | } |
73 | | |
74 | 0 | if (request_len != REND_COOKIE_LEN) { |
75 | 0 | relay_increment_est_rend_action(EST_REND_MALFORMED); |
76 | 0 | log_fn(LOG_PROTOCOL_WARN, |
77 | 0 | LD_PROTOCOL, "Invalid length on ESTABLISH_RENDEZVOUS."); |
78 | 0 | goto err; |
79 | 0 | } |
80 | | |
81 | 0 | if (hs_circuitmap_get_rend_circ_relay_side(request)) { |
82 | 0 | relay_increment_est_rend_action(EST_REND_DUPLICATE_COOKIE); |
83 | 0 | log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, |
84 | 0 | "Duplicate rendezvous cookie in ESTABLISH_RENDEZVOUS."); |
85 | 0 | goto err; |
86 | 0 | } |
87 | | |
88 | | /* Acknowledge the request. */ |
89 | 0 | if (relay_send_command_from_edge(0,TO_CIRCUIT(circ), |
90 | 0 | RELAY_COMMAND_RENDEZVOUS_ESTABLISHED, |
91 | 0 | "", 0, NULL)<0) { |
92 | 0 | relay_increment_est_rend_action(EST_REND_CIRCUIT_DEAD); |
93 | 0 | log_warn(LD_PROTOCOL, "Couldn't send RENDEZVOUS_ESTABLISHED cell."); |
94 | | /* Stop right now, the circuit has been closed. */ |
95 | 0 | return -1; |
96 | 0 | } |
97 | | |
98 | 0 | relay_increment_est_rend_action(EST_REND_SUCCESS); |
99 | 0 | circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_REND_POINT_WAITING); |
100 | 0 | hs_circuitmap_register_rend_circ_relay_side(circ, request); |
101 | |
|
102 | 0 | base16_encode(hexid,9,(char*)request,4); |
103 | |
|
104 | 0 | log_info(LD_REND, |
105 | 0 | "Established rendezvous point on circuit %u for cookie %s", |
106 | 0 | (unsigned)circ->p_circ_id, hexid); |
107 | |
|
108 | 0 | return 0; |
109 | 0 | err: |
110 | 0 | circuit_mark_for_close(TO_CIRCUIT(circ), reason); |
111 | 0 | return -1; |
112 | 0 | } |
113 | | |
114 | | /** Process a RENDEZVOUS1 cell by looking up the correct rendezvous |
115 | | * circuit by its relaying the cell's body in a RENDEZVOUS2 cell, and |
116 | | * connecting the two circuits. |
117 | | */ |
118 | | int |
119 | | rend_mid_rendezvous(or_circuit_t *circ, const uint8_t *request, |
120 | | size_t request_len) |
121 | 0 | { |
122 | 0 | const or_options_t *options = get_options(); |
123 | 0 | or_circuit_t *rend_circ; |
124 | 0 | char hexid[9]; |
125 | 0 | int reason = END_CIRC_REASON_INTERNAL; |
126 | |
|
127 | 0 | if (circ->base_.purpose != CIRCUIT_PURPOSE_OR || circ->base_.n_chan) { |
128 | 0 | relay_increment_rend1_action(REND1_UNSUITABLE_CIRCUIT); |
129 | 0 | log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, |
130 | 0 | "Tried to complete rendezvous on non-OR or non-edge circuit %u.", |
131 | 0 | (unsigned)circ->p_circ_id); |
132 | 0 | reason = END_CIRC_REASON_TORPROTOCOL; |
133 | 0 | goto err; |
134 | 0 | } |
135 | | |
136 | | /* Same for a (pending) conflux leg: its purpose must not change. */ |
137 | 0 | if (circ->base_.conflux || circ->base_.conflux_pending_nonce) { |
138 | 0 | relay_increment_rend1_action(REND1_UNSUITABLE_CIRCUIT); |
139 | 0 | log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, |
140 | 0 | "Tried to complete rendezvous on conflux circuit %u.", |
141 | 0 | (unsigned)circ->p_circ_id); |
142 | 0 | reason = END_CIRC_REASON_TORPROTOCOL; |
143 | 0 | goto err; |
144 | 0 | } |
145 | | |
146 | 0 | if (request_len < REND_COOKIE_LEN) { |
147 | 0 | relay_increment_rend1_action(REND1_MALFORMED); |
148 | 0 | log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, |
149 | 0 | "Rejecting RENDEZVOUS1 cell with bad length (%d) on circuit %u.", |
150 | 0 | (int)request_len, (unsigned)circ->p_circ_id); |
151 | 0 | reason = END_CIRC_REASON_TORPROTOCOL; |
152 | 0 | goto err; |
153 | 0 | } |
154 | | |
155 | 0 | base16_encode(hexid, sizeof(hexid), (const char*)request, 4); |
156 | |
|
157 | 0 | log_info(LD_REND, |
158 | 0 | "Got request for rendezvous from circuit %u to cookie %s.", |
159 | 0 | (unsigned)circ->p_circ_id, hexid); |
160 | |
|
161 | 0 | rend_circ = hs_circuitmap_get_rend_circ_relay_side(request); |
162 | 0 | if (!rend_circ) { |
163 | | /* Once this was a LOG_PROTOCOL_WARN, but it can happen naturally if a |
164 | | * client gives up on a rendezvous circuit after sending INTRODUCE1, but |
165 | | * before the onion service sends the RENDEZVOUS1 cell. |
166 | | */ |
167 | 0 | relay_increment_rend1_action(REND1_UNKNOWN_COOKIE); |
168 | 0 | log_fn(LOG_DEBUG, LD_PROTOCOL, |
169 | 0 | "Rejecting RENDEZVOUS1 cell with unrecognized rendezvous cookie %s.", |
170 | 0 | hexid); |
171 | 0 | reason = END_CIRC_REASON_TORPROTOCOL; |
172 | 0 | goto err; |
173 | 0 | } |
174 | | |
175 | | /* Statistics: Mark circuits as RP circuits */ |
176 | 0 | if (options->HiddenServiceStatistics) { |
177 | | /* `circ` is the RP <-> service circuit */ |
178 | 0 | circ->circuit_carries_hs_traffic_stats = 1; |
179 | | /* `rend_circ` is the client <-> RP circuit */ |
180 | 0 | rend_circ->circuit_carries_hs_traffic_stats = 1; |
181 | 0 | } |
182 | | |
183 | | /* Send the RENDEZVOUS2 cell to the client. */ |
184 | 0 | if (relay_send_command_from_edge(0, TO_CIRCUIT(rend_circ), |
185 | 0 | RELAY_COMMAND_RENDEZVOUS2, |
186 | 0 | (char*)(request+REND_COOKIE_LEN), |
187 | 0 | request_len-REND_COOKIE_LEN, NULL)) { |
188 | 0 | relay_increment_rend1_action(REND1_CIRCUIT_DEAD); |
189 | 0 | log_warn(LD_GENERAL, |
190 | 0 | "Unable to send RENDEZVOUS2 cell to client on circuit %u.", |
191 | 0 | (unsigned)rend_circ->p_circ_id); |
192 | | /* Stop right now, the circuit has been closed. */ |
193 | 0 | return -1; |
194 | 0 | } |
195 | | |
196 | 0 | relay_increment_rend1_action(REND1_SUCCESS); |
197 | | /* Join the circuits. */ |
198 | 0 | log_info(LD_REND, |
199 | 0 | "Completing rendezvous: circuit %u joins circuit %u (cookie %s)", |
200 | 0 | (unsigned)circ->p_circ_id, (unsigned)rend_circ->p_circ_id, hexid); |
201 | |
|
202 | 0 | circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_REND_ESTABLISHED); |
203 | 0 | circuit_change_purpose(TO_CIRCUIT(rend_circ), |
204 | 0 | CIRCUIT_PURPOSE_REND_ESTABLISHED); |
205 | 0 | hs_circuitmap_remove_circuit(TO_CIRCUIT(rend_circ)); |
206 | |
|
207 | 0 | rend_circ->rend_splice = circ; |
208 | 0 | circ->rend_splice = rend_circ; |
209 | |
|
210 | 0 | return 0; |
211 | 0 | err: |
212 | 0 | circuit_mark_for_close(TO_CIRCUIT(circ), reason); |
213 | 0 | return -1; |
214 | 0 | } |