aboutsummaryrefslogtreecommitdiff
path: root/src/core/or/connection_edge.h
blob: 68d8b19a11bd77cad7d27babdd7b2c52412f2dca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
/* Copyright (c) 2001 Matej Pfajfar.
 * Copyright (c) 2001-2004, Roger Dingledine.
 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
 * Copyright (c) 2007-2019, The Tor Project, Inc. */
/* See LICENSE for licensing information */

/**
 * \file connection_edge.h
 * \brief Header file for connection_edge.c.
 **/

#ifndef TOR_CONNECTION_EDGE_H
#define TOR_CONNECTION_EDGE_H

#include "lib/testsupport/testsupport.h"

#include "feature/hs/hs_service.h"

edge_connection_t *TO_EDGE_CONN(connection_t *);
entry_connection_t *TO_ENTRY_CONN(connection_t *);
entry_connection_t *EDGE_TO_ENTRY_CONN(edge_connection_t *);

#define EXIT_CONN_STATE_MIN_ 1
/** State for an exit connection: waiting for response from DNS farm. */
#define EXIT_CONN_STATE_RESOLVING 1
/** State for an exit connection: waiting for connect() to finish. */
#define EXIT_CONN_STATE_CONNECTING 2
/** State for an exit connection: open and ready to transmit data. */
#define EXIT_CONN_STATE_OPEN 3
/** State for an exit connection: waiting to be removed. */
#define EXIT_CONN_STATE_RESOLVEFAILED 4
#define EXIT_CONN_STATE_MAX_ 4

/* The AP state values must be disjoint from the EXIT state values. */
#define AP_CONN_STATE_MIN_ 5
/** State for a SOCKS connection: waiting for SOCKS request. */
#define AP_CONN_STATE_SOCKS_WAIT 5
/** State for a SOCKS connection: got a y.onion URL; waiting to receive
 * rendezvous descriptor. */
#define AP_CONN_STATE_RENDDESC_WAIT 6
/** The controller will attach this connection to a circuit; it isn't our
 * job to do so. */
#define AP_CONN_STATE_CONTROLLER_WAIT 7
/** State for a SOCKS connection: waiting for a completed circuit. */
#define AP_CONN_STATE_CIRCUIT_WAIT 8
/** State for a SOCKS connection: sent BEGIN, waiting for CONNECTED. */
#define AP_CONN_STATE_CONNECT_WAIT 9
/** State for a SOCKS connection: sent RESOLVE, waiting for RESOLVED. */
#define AP_CONN_STATE_RESOLVE_WAIT 10
/** State for a SOCKS connection: ready to send and receive. */
#define AP_CONN_STATE_OPEN 11
/** State for a transparent natd connection: waiting for original
 * destination. */
#define AP_CONN_STATE_NATD_WAIT 12
/** State for an HTTP tunnel: waiting for an HTTP CONNECT command. */
#define AP_CONN_STATE_HTTP_CONNECT_WAIT 13
#define AP_CONN_STATE_MAX_ 13

#define EXIT_PURPOSE_MIN_ 1
/** This exit stream wants to do an ordinary connect. */
#define EXIT_PURPOSE_CONNECT 1
/** This exit stream wants to do a resolve (either normal or reverse). */
#define EXIT_PURPOSE_RESOLVE 2
#define EXIT_PURPOSE_MAX_ 2

/** True iff the AP_CONN_STATE_* value <b>s</b> means that the corresponding
 * edge connection is not attached to any circuit. */
#define AP_CONN_STATE_IS_UNATTACHED(s) \
  ((s) <= AP_CONN_STATE_CIRCUIT_WAIT || (s) == AP_CONN_STATE_NATD_WAIT)

#define connection_mark_unattached_ap(conn, endreason)                  \
  connection_mark_unattached_ap_((conn), (endreason), __LINE__, SHORT_FILE__)

MOCK_DECL(void,connection_mark_unattached_ap_,
          (entry_connection_t *conn, int endreason,
           int line, const char *file));
int connection_edge_reached_eof(edge_connection_t *conn);
int connection_edge_process_inbuf(edge_connection_t *conn,
                                  int package_partial);
int connection_edge_destroy(circid_t circ_id, edge_connection_t *conn);
int connection_edge_end(edge_connection_t *conn, uint8_t reason);
int connection_edge_end_errno(edge_connection_t *conn);
int connection_edge_flushed_some(edge_connection_t *conn);
int connection_edge_finished_flushing(edge_connection_t *conn);
int connection_edge_finished_connecting(edge_connection_t *conn);

void connection_ap_about_to_close(entry_connection_t *edge_conn);
void connection_exit_about_to_close(edge_connection_t *edge_conn);

MOCK_DECL(int,
          connection_ap_handshake_send_begin,(entry_connection_t *ap_conn));
int connection_ap_handshake_send_resolve(entry_connection_t *ap_conn);

entry_connection_t  *connection_ap_make_link(connection_t *partner,
                                            char *address, uint16_t port,
                                            const char *digest,
                                            int session_group,
                                            int isolation_flags,
                                            int use_begindir, int want_onehop);
void connection_ap_handshake_socks_reply(entry_connection_t *conn, char *reply,
                                         size_t replylen,
                                         int endreason);
MOCK_DECL(void,connection_ap_handshake_socks_resolved,
          (entry_connection_t *conn,
           int answer_type,
           size_t answer_len,
           const uint8_t *answer,
           int ttl,
           time_t expires));
void connection_ap_handshake_socks_resolved_addr(entry_connection_t *conn,
                                                 const tor_addr_t *answer,
                                                 int ttl,
                                                 time_t expires);

int connection_exit_begin_conn(cell_t *cell, circuit_t *circ);
int connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ);
void connection_exit_connect(edge_connection_t *conn);
int connection_edge_is_rendezvous_stream(const edge_connection_t *conn);
int connection_ap_can_use_exit(const entry_connection_t *conn,
                               const node_t *exit);
void connection_ap_expire_beginning(void);
void connection_ap_rescan_and_attach_pending(void);
void connection_ap_attach_pending(int retry);
void connection_ap_mark_as_pending_circuit_(entry_connection_t *entry_conn,
                                           const char *file, int line);
#define connection_ap_mark_as_pending_circuit(c) \
  connection_ap_mark_as_pending_circuit_((c), __FILE__, __LINE__)
void connection_ap_mark_as_non_pending_circuit(entry_connection_t *entry_conn);
void connection_ap_mark_as_waiting_for_renddesc(
                                       entry_connection_t *entry_conn);

#define CONNECTION_AP_EXPECT_NONPENDING(c) do {                         \
    if (ENTRY_TO_CONN(c)->state == AP_CONN_STATE_CIRCUIT_WAIT) {        \
      log_warn(LD_BUG, "At %s:%d: %p was unexpectedly in circuit_wait.", \
               __FILE__, __LINE__, (c));                                \
      connection_ap_mark_as_non_pending_circuit(c);                     \
    }                                                                   \
  } while (0)
void connection_ap_fail_onehop(const char *failed_digest,
                               cpath_build_state_t *build_state);
void circuit_discard_optional_exit_enclaves(extend_info_t *info);
int connection_ap_detach_retriable(entry_connection_t *conn,
                                   origin_circuit_t *circ,
                                   int reason);
int connection_ap_process_transparent(entry_connection_t *conn);

int address_is_invalid_destination(const char *address, int client);

MOCK_DECL(int, connection_ap_rewrite_and_attach_if_allowed,
                                                (entry_connection_t *conn,
                                                 origin_circuit_t *circ,
                                                 crypt_path_t *cpath));
int connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
                                               origin_circuit_t *circ,
                                               crypt_path_t *cpath);

/** Possible return values for parse_extended_hostname. */
typedef enum hostname_type_t {
  NORMAL_HOSTNAME, ONION_V2_HOSTNAME, ONION_V3_HOSTNAME,
  EXIT_HOSTNAME, BAD_HOSTNAME
} hostname_type_t;
hostname_type_t parse_extended_hostname(char *address);

#if defined(HAVE_NET_IF_H) && defined(HAVE_NET_PFVAR_H)
int get_pf_socket(void);
#endif

int connection_edge_compatible_with_circuit(const entry_connection_t *conn,
                                            const origin_circuit_t *circ);
int connection_edge_update_circuit_isolation(const entry_connection_t *conn,
                                             origin_circuit_t *circ,
                                             int dry_run);
void circuit_clear_isolation(origin_circuit_t *circ);
streamid_t get_unique_stream_id_by_circ(origin_circuit_t *circ);

void connection_edge_free_all(void);

void connection_ap_warn_and_unmark_if_pending_circ(
                                             entry_connection_t *entry_conn,
                                             const char *where);

int connection_half_edge_is_valid_data(const smartlist_t *half_conns,
                                       streamid_t stream_id);
int connection_half_edge_is_valid_sendme(const smartlist_t *half_conns,
                                         streamid_t stream_id);
int connection_half_edge_is_valid_connected(const smartlist_t *half_conns,
                                            streamid_t stream_id);
int connection_half_edge_is_valid_end(smartlist_t *half_conns,
                                      streamid_t stream_id);
int connection_half_edge_is_valid_resolved(smartlist_t *half_conns,
                                           streamid_t stream_id);

size_t half_streams_get_total_allocation(void);
struct half_edge_t;
void half_edge_free_(struct half_edge_t *he);
#define half_edge_free(he) \
  FREE_AND_NULL(half_edge_t, half_edge_free_, (he))

/** @name Begin-cell flags
 *
 * These flags are used in RELAY_BEGIN cells to change the default behavior
 * of the cell.
 *
 * @{
 **/
/** When this flag is set, the client is willing to get connected to IPv6
 * addresses */
#define BEGIN_FLAG_IPV6_OK        (1u<<0)
/** When this flag is set, the client DOES NOT support connecting to IPv4
 * addresses.  (The sense of this flag is inverted from IPV6_OK, so that the
 * old default behavior of Tor is equivalent to having all flags set to 0.)
 **/
#define BEGIN_FLAG_IPV4_NOT_OK    (1u<<1)
/** When this flag is set, if we find both an IPv4 and an IPv6 address,
 * we use the IPv6 address.  Otherwise we use the IPv4 address. */
#define BEGIN_FLAG_IPV6_PREFERRED (1u<<2)
/**@}*/

#ifdef CONNECTION_EDGE_PRIVATE

/** A parsed BEGIN or BEGIN_DIR cell */
typedef struct begin_cell_t {
  /** The address the client has asked us to connect to, or NULL if this is
   * a BEGIN_DIR cell*/
  char *address;
  /** The flags specified in the BEGIN cell's body.  One or more of
   * BEGIN_FLAG_*. */
  uint32_t flags;
  /** The client's requested port. */
  uint16_t port;
  /** The client's requested Stream ID */
  uint16_t stream_id;
  /** True iff this is a BEGIN_DIR cell. */
  unsigned is_begindir : 1;
} begin_cell_t;

STATIC int begin_cell_parse(const cell_t *cell, begin_cell_t *bcell,
                     uint8_t *end_reason_out);
STATIC int connected_cell_format_payload(uint8_t *payload_out,
                                  const tor_addr_t *addr,
                                  uint32_t ttl);

typedef struct {
  /** Original address, after we lowercased it but before we started
   * mapping it.
   */
  char orig_address[MAX_SOCKS_ADDR_LEN];
  /** True iff the address has been automatically remapped to a local
   * address in VirtualAddrNetwork.  (Only set true when we do a resolve
   * and get a virtual address; not when we connect to the address.) */
  int automap;
  /** If this connection has a .exit address, who put it there? */
  addressmap_entry_source_t exit_source;
  /** If we've rewritten the address, when does this map expire? */
  time_t map_expires;
  /** If we should close the connection, this is the end_reason to pass
   * to connection_mark_unattached_ap */
  int end_reason;
  /** True iff we should close the connection, either because of error or
   * because of successful early RESOLVED reply. */
  int should_close;
} rewrite_result_t;

STATIC void connection_ap_handshake_rewrite(entry_connection_t *conn,
                                            rewrite_result_t *out);

STATIC int connection_ap_process_http_connect(entry_connection_t *conn);
STATIC void export_hs_client_circuit_id(edge_connection_t *edge_conn,
                            hs_circuit_id_protocol_t protocol);

struct half_edge_t;
STATIC void connection_half_edge_add(const edge_connection_t *conn,
                                     origin_circuit_t *circ);
STATIC struct half_edge_t *connection_half_edge_find_stream_id(
                                     const smartlist_t *half_conns,
                                     streamid_t stream_id);
#endif /* defined(CONNECTION_EDGE_PRIVATE) */

#endif /* !defined(TOR_CONNECTION_EDGE_H) */