/src/h2o/lib/handler/connect.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2021 Fastly Inc. |
3 | | * |
4 | | * Permission is hereby granted, free of charge, to any person obtaining a copy |
5 | | * of this software and associated documentation files (the "Software"), to |
6 | | * deal in the Software without restriction, including without limitation the |
7 | | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
8 | | * sell copies of the Software, and to permit persons to whom the Software is |
9 | | * furnished to do so, subject to the following conditions: |
10 | | * |
11 | | * The above copyright notice and this permission notice shall be included in |
12 | | * all copies or substantial portions of the Software. |
13 | | * |
14 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
15 | | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
16 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
17 | | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
18 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
19 | | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
20 | | * IN THE SOFTWARE. |
21 | | */ |
22 | | #include "h2o/hostinfo.h" |
23 | | #include "h2o/memory.h" |
24 | | #include "h2o/socket.h" |
25 | | #include "h2o.h" |
26 | | #include "../probes_.h" |
27 | | |
28 | 0 | #define MODULE_NAME "lib/handler/connect.c" |
29 | | |
30 | | struct st_connect_handler_t { |
31 | | h2o_handler_t super; |
32 | | h2o_proxy_config_vars_t config; |
33 | | struct { |
34 | | size_t count; |
35 | | h2o_connect_acl_entry_t entries[0]; |
36 | | } acl; |
37 | | }; |
38 | | |
39 | 0 | #define MAX_ADDRESSES_PER_FAMILY 4 |
40 | 0 | #define UDP_CHUNK_OVERHEAD 10 /* sufficient space to hold DATAGRAM capsule header (RFC 9297) and context ID of zero (RFC 9298) */ |
41 | | |
42 | | struct st_server_address_t { |
43 | | struct sockaddr *sa; |
44 | | socklen_t salen; |
45 | | }; |
46 | | |
47 | | struct st_connect_generator_t { |
48 | | h2o_generator_t super; |
49 | | struct st_connect_handler_t *handler; |
50 | | h2o_req_t *src_req; |
51 | | |
52 | | struct { |
53 | | h2o_hostinfo_getaddr_req_t *v4, *v6; |
54 | | } getaddr_req; |
55 | | struct { |
56 | | struct st_server_address_t list[MAX_ADDRESSES_PER_FAMILY * 2]; |
57 | | size_t size; |
58 | | size_t used; |
59 | | } server_addresses; |
60 | | |
61 | | h2o_socket_t *sock; |
62 | | /** |
63 | | * Most significant and latest error that occurred, if any. Significance is represented as `class`, in descending order. |
64 | | */ |
65 | | struct { |
66 | | enum error_class { ERROR_CLASS_NAME_RESOLUTION, ERROR_CLASS_ACCESS_PROHIBITED, ERROR_CLASS_CONNECT } class; |
67 | | const char *str; |
68 | | } last_error; |
69 | | |
70 | | /** |
71 | | * timer used to handle user-visible timeouts (i.e., connect- and io-timeout) |
72 | | */ |
73 | | h2o_timer_t timeout; |
74 | | /** |
75 | | * timer used to for RFC 8305-style happy eyeballs (resolution delay and connection attempt delay) |
76 | | */ |
77 | | h2o_timer_t eyeball_delay; |
78 | | |
79 | | /** |
80 | | * Pick v4 (or v6) address in the next connection attempt. RFC 8305 recommends trying the other family one by one. |
81 | | */ |
82 | | unsigned pick_v4 : 1; |
83 | | /** |
84 | | * `h2o_process_request` was called without request streaming; all data that have to be sent is inside `h2o_req_t::entity` |
85 | | */ |
86 | | unsigned no_req_streaming : 1; |
87 | | /** |
88 | | * set when the send-side is closed by the user |
89 | | */ |
90 | | unsigned write_closed : 1; |
91 | | /** |
92 | | * set when h2o_send has been called to notify that the socket has been closed |
93 | | */ |
94 | | unsigned read_closed : 1; |
95 | | /** |
96 | | * if socket has been closed |
97 | | */ |
98 | | unsigned socket_closed : 1; |
99 | | /** |
100 | | * if connecting using TCP (or UDP) |
101 | | */ |
102 | | unsigned is_tcp : 1; |
103 | | /** |
104 | | * TCP- and UDP-specific data |
105 | | */ |
106 | | union { |
107 | | struct { |
108 | | h2o_buffer_t *sendbuf; |
109 | | h2o_buffer_t *recvbuf_detached; |
110 | | } tcp; |
111 | | struct { |
112 | | struct { |
113 | | h2o_buffer_t *buf; /* for datagram fragments */ |
114 | | h2o_timer_t delayed; |
115 | | } egress; |
116 | | struct { |
117 | | char buf[UDP_CHUNK_OVERHEAD + 1500]; |
118 | | } ingress; |
119 | | /** |
120 | | * if using draft-03 style encoding rather than RFC 9298 |
121 | | */ |
122 | | unsigned is_draft03 : 1; |
123 | | } udp; |
124 | | }; |
125 | | }; |
126 | | |
127 | | static h2o_iovec_t get_proxy_status_identity(h2o_req_t *req) |
128 | 0 | { |
129 | 0 | h2o_iovec_t identity = req->conn->ctx->globalconf->proxy_status_identity; |
130 | 0 | if (identity.base == NULL) |
131 | 0 | identity = h2o_iovec_init(H2O_STRLIT("h2o")); |
132 | 0 | return identity; |
133 | 0 | } |
134 | | |
135 | | static const struct st_server_address_t *get_dest_addr(struct st_connect_generator_t *self) |
136 | 0 | { |
137 | 0 | if (self->server_addresses.used > 0) { |
138 | 0 | return &self->server_addresses.list[self->server_addresses.used - 1]; |
139 | 0 | } else { |
140 | 0 | return NULL; |
141 | 0 | } |
142 | 0 | } |
143 | | |
144 | | static void add_proxy_status_header(struct st_connect_handler_t *handler, h2o_req_t *req, const char *error_type, |
145 | | const char *details, const char *rcode, h2o_iovec_t dest_addr_str) |
146 | 0 | { |
147 | 0 | if (!handler->config.connect_proxy_status_enabled) |
148 | 0 | return; |
149 | | |
150 | 0 | h2o_mem_pool_t *pool = &req->pool; |
151 | 0 | h2o_iovec_t parts[9] = { |
152 | 0 | get_proxy_status_identity(req), |
153 | 0 | }; |
154 | 0 | size_t nparts = 1; |
155 | 0 | if (error_type != NULL) { |
156 | 0 | parts[nparts++] = h2o_iovec_init(H2O_STRLIT("; error=")); |
157 | 0 | parts[nparts++] = h2o_iovec_init(error_type, strlen(error_type)); |
158 | 0 | } |
159 | 0 | if (rcode != NULL) { |
160 | 0 | parts[nparts++] = h2o_iovec_init(H2O_STRLIT("; rcode=")); |
161 | 0 | parts[nparts++] = h2o_iovec_init(rcode, strlen(rcode)); |
162 | 0 | } |
163 | 0 | if (details != NULL) { |
164 | 0 | parts[nparts++] = h2o_iovec_init(H2O_STRLIT("; details=")); |
165 | 0 | parts[nparts++] = h2o_encode_sf_string(pool, details, SIZE_MAX); |
166 | 0 | } |
167 | 0 | if (dest_addr_str.base != NULL) { |
168 | 0 | parts[nparts++] = h2o_iovec_init(H2O_STRLIT("; next-hop=")); |
169 | 0 | parts[nparts++] = dest_addr_str; |
170 | 0 | } |
171 | 0 | assert(nparts <= sizeof(parts) / sizeof(parts[0])); |
172 | 0 | h2o_iovec_t hval = h2o_concat_list(pool, parts, nparts); |
173 | 0 | h2o_add_header_by_str(pool, &req->res.headers, H2O_STRLIT("proxy-status"), 0, NULL, hval.base, hval.len); |
174 | 0 | } |
175 | | |
176 | 0 | #define TO_BITMASK(type, len) ((type) ~(((type)1 << (sizeof(type) * 8 - (len))) - 1)) |
177 | | |
178 | | static void record_error(struct st_connect_handler_t *handler, h2o_req_t *req, const struct st_server_address_t *addr, |
179 | | const char *error_type, const char *details, const char *rcode) |
180 | 0 | { |
181 | 0 | H2O_PROBE_REQUEST(CONNECT_ERROR, req, error_type, details, rcode); |
182 | |
|
183 | 0 | char dest_addr_strbuf[NI_MAXHOST]; |
184 | 0 | h2o_iovec_t dest_addr_str = h2o_iovec_init(NULL, 0); |
185 | 0 | if (addr != NULL) { |
186 | 0 | size_t len = h2o_socket_getnumerichost(addr->sa, addr->salen, dest_addr_strbuf); |
187 | 0 | if (len != SIZE_MAX) { |
188 | 0 | dest_addr_str = h2o_iovec_init(dest_addr_strbuf, len); |
189 | 0 | } |
190 | 0 | } |
191 | |
|
192 | 0 | h2o_req_log_error(req, MODULE_NAME, "%s; rcode=%s; details=%s; next-hop=%s", error_type, rcode != NULL ? rcode : "(null)", |
193 | 0 | details != NULL ? details : "(null)", dest_addr_str.base != NULL ? dest_addr_str.base : "(null)"); |
194 | |
|
195 | 0 | add_proxy_status_header(handler, req, error_type, details, rcode, dest_addr_str); |
196 | 0 | } |
197 | | |
198 | | static void record_connect_success(struct st_connect_generator_t *self) |
199 | 0 | { |
200 | 0 | const struct st_server_address_t *addr = get_dest_addr(self); |
201 | 0 | if (addr == NULL) |
202 | 0 | return; |
203 | | |
204 | 0 | H2O_PROBE_REQUEST(CONNECT_SUCCESS, self->src_req, addr->sa); |
205 | |
|
206 | 0 | char dest_addr_strbuf[NI_MAXHOST]; |
207 | 0 | size_t len = h2o_socket_getnumerichost(addr->sa, addr->salen, dest_addr_strbuf); |
208 | 0 | if (len != SIZE_MAX) { |
209 | 0 | add_proxy_status_header(self->handler, self->src_req, NULL, NULL, NULL, h2o_iovec_init(dest_addr_strbuf, len)); |
210 | 0 | } |
211 | 0 | } |
212 | | |
213 | | static void record_socket_error(struct st_connect_generator_t *self, const char *err) |
214 | 0 | { |
215 | 0 | const char *error_type; |
216 | 0 | const char *details = NULL; |
217 | 0 | if (err == h2o_socket_error_conn_refused) |
218 | 0 | error_type = "connection_refused"; |
219 | 0 | else if (err == h2o_socket_error_conn_timed_out) |
220 | 0 | error_type = "connection_timeout"; |
221 | 0 | else if (err == h2o_socket_error_network_unreachable || err == h2o_socket_error_host_unreachable) |
222 | 0 | error_type = "destination_ip_unroutable"; |
223 | 0 | else { |
224 | 0 | error_type = "proxy_internal_error"; |
225 | 0 | details = err; |
226 | 0 | } |
227 | 0 | record_error(self->handler, self->src_req, get_dest_addr(self), error_type, details, NULL); |
228 | 0 | } |
229 | | |
230 | | static void try_connect(struct st_connect_generator_t *self); |
231 | | static int tcp_start_connect(struct st_connect_generator_t *self, struct st_server_address_t *server_address); |
232 | | static int udp_connect(struct st_connect_generator_t *self, struct st_server_address_t *server_address); |
233 | | |
234 | | static h2o_loop_t *get_loop(struct st_connect_generator_t *self) |
235 | 0 | { |
236 | 0 | return self->src_req->conn->ctx->loop; |
237 | 0 | } |
238 | | |
239 | | static void stop_eyeballs(struct st_connect_generator_t *self) |
240 | 0 | { |
241 | 0 | if (self->getaddr_req.v4 != NULL) { |
242 | 0 | h2o_hostinfo_getaddr_cancel(self->getaddr_req.v4); |
243 | 0 | self->getaddr_req.v4 = NULL; |
244 | 0 | } |
245 | 0 | if (self->getaddr_req.v6 != NULL) { |
246 | 0 | h2o_hostinfo_getaddr_cancel(self->getaddr_req.v6); |
247 | 0 | self->getaddr_req.v6 = NULL; |
248 | 0 | } |
249 | 0 | if (self->eyeball_delay.cb != NULL) { |
250 | 0 | h2o_timer_unlink(&self->eyeball_delay); |
251 | 0 | self->eyeball_delay.cb = NULL; |
252 | 0 | } |
253 | 0 | } |
254 | | |
255 | | static void dispose_generator(struct st_connect_generator_t *self) |
256 | 0 | { |
257 | 0 | stop_eyeballs(self); |
258 | 0 | if (self->sock != NULL) { |
259 | 0 | h2o_socket_close(self->sock); |
260 | 0 | self->sock = NULL; |
261 | 0 | self->socket_closed = 1; |
262 | 0 | } |
263 | 0 | if (self->is_tcp) { |
264 | 0 | if (self->tcp.sendbuf != NULL) |
265 | 0 | h2o_buffer_dispose(&self->tcp.sendbuf); |
266 | 0 | if (self->tcp.recvbuf_detached != NULL) |
267 | 0 | h2o_buffer_dispose(&self->tcp.recvbuf_detached); |
268 | 0 | } else { |
269 | 0 | if (self->udp.egress.buf != NULL) |
270 | 0 | h2o_buffer_dispose(&self->udp.egress.buf); |
271 | 0 | h2o_timer_unlink(&self->udp.egress.delayed); |
272 | 0 | } |
273 | 0 | h2o_timer_unlink(&self->timeout); |
274 | 0 | } |
275 | | |
276 | | static int close_socket(struct st_connect_generator_t *self) |
277 | 0 | { |
278 | 0 | int send_inflight; |
279 | |
|
280 | 0 | if (self->is_tcp) { |
281 | 0 | self->tcp.recvbuf_detached = self->sock->input; |
282 | 0 | send_inflight = self->tcp.recvbuf_detached->size != 0; |
283 | 0 | } else { |
284 | 0 | send_inflight = !h2o_socket_is_reading(self->sock); |
285 | 0 | } |
286 | 0 | h2o_buffer_init(&self->sock->input, &h2o_socket_buffer_prototype); |
287 | 0 | h2o_socket_close(self->sock); |
288 | 0 | self->sock = NULL; |
289 | 0 | self->socket_closed = 1; |
290 | |
|
291 | 0 | return send_inflight; |
292 | 0 | } |
293 | | |
294 | | static void close_readwrite(struct st_connect_generator_t *self) |
295 | 0 | { |
296 | 0 | int send_inflight = 0; |
297 | |
|
298 | 0 | if (self->sock != NULL) |
299 | 0 | send_inflight = close_socket(self); |
300 | 0 | else if (self->is_tcp) |
301 | 0 | send_inflight = self->tcp.recvbuf_detached->size != 0; |
302 | |
|
303 | 0 | if (h2o_timer_is_linked(&self->timeout)) |
304 | 0 | h2o_timer_unlink(&self->timeout); |
305 | | |
306 | | /* immediately notify read-close if necessary, setting up delayed task to for destroying other items; the timer is reset if |
307 | | * `h2o_send` indirectly invokes `dispose_generator`. */ |
308 | 0 | if (!self->read_closed && !send_inflight) { |
309 | 0 | h2o_timer_link(get_loop(self), 0, &self->timeout); |
310 | 0 | self->read_closed = 1; |
311 | 0 | h2o_send(self->src_req, NULL, 0, H2O_SEND_STATE_FINAL); |
312 | 0 | return; |
313 | 0 | } |
314 | | |
315 | | /* notify write-close if necessary; see the comment above regarding the use of the timer */ |
316 | 0 | if (!self->write_closed && self->is_tcp && self->tcp.sendbuf->size != 0) { |
317 | 0 | self->write_closed = 1; |
318 | 0 | h2o_timer_link(get_loop(self), 0, &self->timeout); |
319 | 0 | self->src_req->proceed_req(self->src_req, h2o_httpclient_error_io /* TODO notify as cancel? */); |
320 | 0 | return; |
321 | 0 | } |
322 | 0 | } |
323 | | |
324 | | static void on_io_timeout(h2o_timer_t *timer) |
325 | 0 | { |
326 | 0 | struct st_connect_generator_t *self = H2O_STRUCT_FROM_MEMBER(struct st_connect_generator_t, timeout, timer); |
327 | 0 | H2O_PROBE_REQUEST0(CONNECT_IO_TIMEOUT, self->src_req); |
328 | 0 | close_readwrite(self); |
329 | 0 | } |
330 | | |
331 | | static void reset_io_timeout(struct st_connect_generator_t *self) |
332 | 0 | { |
333 | 0 | if (self->sock != NULL) { |
334 | 0 | h2o_timer_unlink(&self->timeout); |
335 | 0 | h2o_timer_link(get_loop(self), self->handler->config.io_timeout, &self->timeout); |
336 | 0 | } |
337 | 0 | } |
338 | | |
339 | | static void send_connect_error(struct st_connect_generator_t *self, int code, const char *msg, const char *errstr) |
340 | 0 | { |
341 | 0 | stop_eyeballs(self); |
342 | 0 | h2o_timer_unlink(&self->timeout); |
343 | |
|
344 | 0 | if (self->sock != NULL) { |
345 | 0 | h2o_socket_close(self->sock); |
346 | 0 | self->sock = NULL; |
347 | 0 | } |
348 | |
|
349 | 0 | h2o_send_error_generic(self->src_req, code, msg, errstr, H2O_SEND_ERROR_KEEP_HEADERS); |
350 | 0 | } |
351 | | |
352 | | static void on_connect_error(struct st_connect_generator_t *self, const char *errstr) |
353 | 0 | { |
354 | 0 | send_connect_error(self, 502, "Gateway Error", errstr); |
355 | 0 | } |
356 | | |
357 | | static void on_connect_timeout(h2o_timer_t *entry) |
358 | 0 | { |
359 | 0 | struct st_connect_generator_t *self = H2O_STRUCT_FROM_MEMBER(struct st_connect_generator_t, timeout, entry); |
360 | 0 | if (self->server_addresses.size > 0) { |
361 | 0 | record_error(self->handler, self->src_req, get_dest_addr(self), "connection_timeout", NULL, NULL); |
362 | 0 | } else { |
363 | 0 | record_error(self->handler, self->src_req, NULL, "dns_timeout", NULL, NULL); |
364 | 0 | } |
365 | 0 | on_connect_error(self, h2o_httpclient_error_io_timeout); |
366 | 0 | } |
367 | | |
368 | | static void set_last_error(struct st_connect_generator_t *self, enum error_class class, const char *str) |
369 | 0 | { |
370 | 0 | if (self->last_error.class <= class) { |
371 | 0 | self->last_error.class = class; |
372 | 0 | self->last_error.str = str; |
373 | 0 | } |
374 | 0 | } |
375 | | |
376 | | static void on_resolution_delay_timeout(h2o_timer_t *entry) |
377 | 0 | { |
378 | 0 | struct st_connect_generator_t *self = H2O_STRUCT_FROM_MEMBER(struct st_connect_generator_t, eyeball_delay, entry); |
379 | |
|
380 | 0 | assert(self->server_addresses.used == 0); |
381 | | |
382 | 0 | try_connect(self); |
383 | 0 | } |
384 | | |
385 | | static void on_connection_attempt_delay_timeout(h2o_timer_t *entry) |
386 | 0 | { |
387 | 0 | struct st_connect_generator_t *self = H2O_STRUCT_FROM_MEMBER(struct st_connect_generator_t, eyeball_delay, entry); |
388 | | |
389 | | /* If no more addresses are available, continue trying the current attempt until the connect_timeout expires. */ |
390 | 0 | if (self->server_addresses.used == self->server_addresses.size) |
391 | 0 | return; |
392 | | |
393 | | /* close current connection attempt and try next. */ |
394 | 0 | h2o_socket_close(self->sock); |
395 | 0 | self->sock = NULL; |
396 | 0 | try_connect(self); |
397 | 0 | } |
398 | | |
399 | | static int store_server_addresses(struct st_connect_generator_t *self, struct addrinfo *res) |
400 | 0 | { |
401 | 0 | size_t num_added = 0; |
402 | | |
403 | | /* copy first entries in the response; ordering of addresses being returned by `getaddrinfo` is respected, as ordinary clients |
404 | | * (incl. forward proxy) are not expected to distribute the load among the addresses being returned. */ |
405 | 0 | do { |
406 | 0 | assert(self->server_addresses.size < PTLS_ELEMENTSOF(self->server_addresses.list)); |
407 | 0 | if (h2o_connect_lookup_acl(self->handler->acl.entries, self->handler->acl.count, res->ai_addr)) { |
408 | 0 | struct st_server_address_t *dst = self->server_addresses.list + self->server_addresses.size++; |
409 | 0 | dst->sa = h2o_mem_alloc_pool_aligned(&self->src_req->pool, H2O_ALIGNOF(struct sockaddr), res->ai_addrlen); |
410 | 0 | memcpy(dst->sa, res->ai_addr, res->ai_addrlen); |
411 | 0 | dst->salen = res->ai_addrlen; |
412 | 0 | ++num_added; |
413 | 0 | } |
414 | 0 | } while ((res = res->ai_next) != NULL && num_added < MAX_ADDRESSES_PER_FAMILY); |
415 | | |
416 | 0 | return num_added != 0; |
417 | 0 | } |
418 | | |
419 | | static void on_getaddr(h2o_hostinfo_getaddr_req_t *getaddr_req, const char *errstr, struct addrinfo *res, void *_self) |
420 | 0 | { |
421 | 0 | struct st_connect_generator_t *self = _self; |
422 | 0 | if (getaddr_req == self->getaddr_req.v4) { |
423 | 0 | self->getaddr_req.v4 = NULL; |
424 | 0 | } else if (getaddr_req == self->getaddr_req.v6) { |
425 | 0 | self->getaddr_req.v6 = NULL; |
426 | 0 | } else { |
427 | 0 | h2o_fatal("unexpected getaddr_req"); |
428 | 0 | } |
429 | | |
430 | | /* Store addresses, or convert error to ACL denial. */ |
431 | 0 | if (errstr == NULL) { |
432 | 0 | if (self->is_tcp) { |
433 | 0 | assert(res->ai_socktype == SOCK_STREAM); |
434 | 0 | } else { |
435 | 0 | assert(res->ai_socktype == SOCK_DGRAM); |
436 | 0 | } |
437 | 0 | assert(res != NULL && "upon successful return, getaddrinfo shall return at least one address (RFC 3493 Section 6.1)"); |
438 | 0 | if (!store_server_addresses(self, res)) |
439 | 0 | set_last_error(self, ERROR_CLASS_ACCESS_PROHIBITED, "destination_ip_prohibited"); |
440 | 0 | } else { |
441 | 0 | set_last_error(self, ERROR_CLASS_NAME_RESOLUTION, errstr); |
442 | 0 | } |
443 | | |
444 | 0 | if (self->getaddr_req.v4 == NULL) { |
445 | | /* If v6 lookup is still running, that means that v4 lookup has *just* completed. Set the resolution delay timer if v4 |
446 | | * addresses are available. */ |
447 | 0 | if (self->getaddr_req.v6 != NULL) { |
448 | 0 | assert(self->server_addresses.used == 0); |
449 | 0 | if (self->server_addresses.size != 0) { |
450 | 0 | self->eyeball_delay.cb = on_resolution_delay_timeout; |
451 | 0 | h2o_timer_link(get_loop(self), self->handler->config.happy_eyeballs.name_resolution_delay, &self->eyeball_delay); |
452 | 0 | } |
453 | 0 | return; |
454 | 0 | } |
455 | | |
456 | | /* Both v4 and v6 lookups are complete. If the resolution delay timer is running. Reset it. */ |
457 | 0 | if (h2o_timer_is_linked(&self->eyeball_delay) && self->eyeball_delay.cb == on_resolution_delay_timeout) { |
458 | 0 | assert(self->server_addresses.used == 0); |
459 | 0 | h2o_timer_unlink(&self->eyeball_delay); |
460 | 0 | } |
461 | | /* In case no addresses are available, send HTTP error. */ |
462 | 0 | if (self->server_addresses.size == 0) { |
463 | 0 | if (self->last_error.class == ERROR_CLASS_ACCESS_PROHIBITED) { |
464 | 0 | record_error(self->handler, self->src_req, NULL, self->last_error.str, NULL, NULL); |
465 | 0 | send_connect_error(self, 403, "Destination IP Prohibited", "Destination IP Prohibited"); |
466 | 0 | } else { |
467 | 0 | const char *rcode; |
468 | 0 | if (self->last_error.str == h2o_hostinfo_error_nxdomain) { |
469 | 0 | rcode = "NXDOMAIN"; |
470 | 0 | } else if (self->last_error.str == h2o_hostinfo_error_nodata) { |
471 | 0 | rcode = "NODATA"; |
472 | 0 | } else if (self->last_error.str == h2o_hostinfo_error_refused) { |
473 | 0 | rcode = "REFUSED"; |
474 | 0 | } else if (self->last_error.str == h2o_hostinfo_error_servfail) { |
475 | 0 | rcode = "SERVFAIL"; |
476 | 0 | } else { |
477 | 0 | rcode = NULL; |
478 | 0 | } |
479 | 0 | record_error(self->handler, self->src_req, NULL, "dns_error", self->last_error.str, rcode); |
480 | 0 | on_connect_error(self, self->last_error.str); |
481 | 0 | } |
482 | 0 | return; |
483 | 0 | } |
484 | 0 | } |
485 | | |
486 | | /* If the connection attempt has been under way for more than CONNECTION_ATTEMPT_DELAY_MS and the lookup that just completed |
487 | | * gave us a new address to try, then stop that connection attempt and start a new connection attempt using the new address. |
488 | | * |
489 | | * If the connection attempt has been under way for less than that, then do nothing for now. Eventually, either the timeout |
490 | | * will expire or the connection attempt will complete. |
491 | | * |
492 | | * If the connection attempt is under way but the lookup has not provided us any new address to try, then do nothing for now, |
493 | | * and wait for the connection attempt to complete. */ |
494 | 0 | if (self->sock != NULL) { |
495 | 0 | if (h2o_timer_is_linked(&self->eyeball_delay)) |
496 | 0 | return; |
497 | 0 | if (self->server_addresses.used == self->server_addresses.size) |
498 | 0 | return; |
499 | 0 | h2o_socket_close(self->sock); |
500 | 0 | self->sock = NULL; |
501 | 0 | } |
502 | 0 | try_connect(self); |
503 | 0 | } |
504 | | |
505 | | static struct st_server_address_t *pick_and_swap(struct st_connect_generator_t *self, size_t idx) |
506 | 0 | { |
507 | 0 | struct st_server_address_t *server_address = NULL; |
508 | |
|
509 | 0 | if (idx != self->server_addresses.used) { |
510 | 0 | struct st_server_address_t swap = self->server_addresses.list[idx]; |
511 | 0 | self->server_addresses.list[idx] = self->server_addresses.list[self->server_addresses.used]; |
512 | 0 | self->server_addresses.list[self->server_addresses.used] = swap; |
513 | 0 | } |
514 | 0 | server_address = &self->server_addresses.list[self->server_addresses.used]; |
515 | 0 | self->server_addresses.used++; |
516 | 0 | self->pick_v4 = !self->pick_v4; |
517 | 0 | return server_address; |
518 | 0 | } |
519 | | |
520 | | static void try_connect(struct st_connect_generator_t *self) |
521 | 0 | { |
522 | 0 | struct st_server_address_t *server_address; |
523 | |
|
524 | 0 | do { |
525 | 0 | server_address = NULL; |
526 | | |
527 | | /* Fetch the next address from the list of resolved addresses. */ |
528 | 0 | for (size_t i = self->server_addresses.used; i < self->server_addresses.size; i++) { |
529 | 0 | if (self->pick_v4 && self->server_addresses.list[i].sa->sa_family == AF_INET) |
530 | 0 | server_address = pick_and_swap(self, i); |
531 | 0 | else if (!self->pick_v4 && self->server_addresses.list[i].sa->sa_family == AF_INET6) |
532 | 0 | server_address = pick_and_swap(self, i); |
533 | 0 | } |
534 | | |
535 | | /* If address of the preferred address family is not available, select one of the other family, if available. Otherwise, |
536 | | * send an HTTP error response or wait for address resolution. */ |
537 | 0 | if (server_address == NULL) { |
538 | 0 | if (self->server_addresses.used == self->server_addresses.size) { |
539 | 0 | if (self->getaddr_req.v4 == NULL && self->getaddr_req.v6 == NULL) { |
540 | 0 | assert(self->last_error.class == ERROR_CLASS_CONNECT); |
541 | 0 | record_socket_error(self, self->last_error.str); |
542 | 0 | on_connect_error(self, self->last_error.str); |
543 | 0 | } |
544 | 0 | return; |
545 | 0 | } |
546 | 0 | server_address = &self->server_addresses.list[self->server_addresses.used]; |
547 | 0 | self->server_addresses.used++; |
548 | 0 | } |
549 | | |
550 | | /* Connect. Retry if the connect function returns error immediately. */ |
551 | 0 | } while (!(self->is_tcp ? tcp_start_connect : udp_connect)(self, server_address)); |
552 | 0 | } |
553 | | |
554 | | static void tcp_on_write_complete(h2o_socket_t *_sock, const char *err) |
555 | 0 | { |
556 | 0 | struct st_connect_generator_t *self = _sock->data; |
557 | |
|
558 | 0 | if (err != NULL) { |
559 | 0 | H2O_PROBE_REQUEST(CONNECT_TCP_WRITE_ERROR, self->src_req, err); |
560 | 0 | } |
561 | | |
562 | | /* until h2o_socket_t implements shutdown(SHUT_WR), do a bidirectional close when we close the write-side */ |
563 | 0 | if (err != NULL || self->write_closed) { |
564 | 0 | close_readwrite(self); |
565 | 0 | return; |
566 | 0 | } |
567 | | |
568 | 0 | reset_io_timeout(self); |
569 | |
|
570 | 0 | h2o_buffer_consume(&self->tcp.sendbuf, self->tcp.sendbuf->size); |
571 | 0 | self->src_req->proceed_req(self->src_req, NULL); |
572 | 0 | } |
573 | | |
574 | | static void tcp_do_write(struct st_connect_generator_t *self) |
575 | 0 | { |
576 | 0 | reset_io_timeout(self); |
577 | |
|
578 | 0 | h2o_iovec_t vec = h2o_iovec_init(self->tcp.sendbuf->bytes, self->tcp.sendbuf->size); |
579 | 0 | H2O_PROBE_REQUEST(CONNECT_TCP_WRITE, self->src_req, vec.len); |
580 | 0 | h2o_socket_write(self->sock, &vec, 1, tcp_on_write_complete); |
581 | 0 | } |
582 | | |
583 | | static int tcp_write(void *_self, int is_end_stream) |
584 | 0 | { |
585 | 0 | struct st_connect_generator_t *self = _self; |
586 | 0 | h2o_iovec_t chunk = self->src_req->entity; |
587 | |
|
588 | 0 | assert(!self->write_closed); |
589 | 0 | assert(self->tcp.sendbuf->size == 0); |
590 | | |
591 | | /* the socket might have been closed due to a read error */ |
592 | 0 | if (self->socket_closed) |
593 | 0 | return 1; |
594 | | |
595 | 0 | assert(self->sock != NULL && "write_req called before proceed_req is called?"); |
596 | | |
597 | | /* buffer input */ |
598 | 0 | h2o_buffer_append(&self->tcp.sendbuf, chunk.base, chunk.len); |
599 | 0 | if (is_end_stream) |
600 | 0 | self->write_closed = 1; |
601 | | |
602 | | /* write if the socket has been opened */ |
603 | 0 | if (self->sock != NULL && !h2o_socket_is_writing(self->sock)) |
604 | 0 | tcp_do_write(self); |
605 | |
|
606 | 0 | return 0; |
607 | 0 | } |
608 | | |
609 | | static void tcp_on_read(h2o_socket_t *_sock, const char *err) |
610 | 0 | { |
611 | 0 | struct st_connect_generator_t *self = _sock->data; |
612 | |
|
613 | 0 | h2o_socket_read_stop(self->sock); |
614 | 0 | h2o_timer_unlink(&self->timeout); |
615 | |
|
616 | 0 | if (err == NULL) { |
617 | 0 | h2o_iovec_t vec = h2o_iovec_init(self->sock->input->bytes, self->sock->input->size); |
618 | 0 | H2O_PROBE_REQUEST(CONNECT_TCP_READ, self->src_req, vec.len); |
619 | 0 | h2o_send(self->src_req, &vec, 1, H2O_SEND_STATE_IN_PROGRESS); |
620 | 0 | } else { |
621 | 0 | H2O_PROBE_REQUEST(CONNECT_TCP_READ_ERROR, self->src_req, err); |
622 | | /* unidirectional close is signalled using H2O_SEND_STATE_FINAL, but the write side remains open */ |
623 | 0 | self->read_closed = 1; |
624 | 0 | h2o_send(self->src_req, NULL, 0, H2O_SEND_STATE_FINAL); |
625 | 0 | } |
626 | 0 | } |
627 | | |
628 | | static void tcp_on_proceed(h2o_generator_t *_self, h2o_req_t *req) |
629 | 0 | { |
630 | 0 | struct st_connect_generator_t *self = H2O_STRUCT_FROM_MEMBER(struct st_connect_generator_t, super, _self); |
631 | |
|
632 | 0 | assert(!self->read_closed); |
633 | | |
634 | 0 | if (self->sock != NULL) { |
635 | 0 | h2o_buffer_consume(&self->sock->input, self->sock->input->size); |
636 | 0 | reset_io_timeout(self); |
637 | 0 | h2o_socket_read_start(self->sock, tcp_on_read); |
638 | 0 | } else { |
639 | 0 | self->read_closed = 1; |
640 | 0 | h2o_send(self->src_req, NULL, 0, H2O_SEND_STATE_FINAL); |
641 | 0 | } |
642 | 0 | } |
643 | | |
644 | | static void tcp_on_connect(h2o_socket_t *_sock, const char *err) |
645 | 0 | { |
646 | 0 | struct st_connect_generator_t *self = _sock->data; |
647 | |
|
648 | 0 | assert(self->sock == _sock); |
649 | | |
650 | 0 | if (err != NULL) { |
651 | 0 | set_last_error(self, ERROR_CLASS_CONNECT, err); |
652 | 0 | h2o_socket_close(self->sock); |
653 | 0 | self->sock = NULL; |
654 | 0 | try_connect(self); |
655 | 0 | return; |
656 | 0 | } |
657 | | |
658 | 0 | stop_eyeballs(self); |
659 | 0 | self->timeout.cb = on_io_timeout; |
660 | 0 | reset_io_timeout(self); |
661 | | |
662 | | /* Start write. Once write is complete (or if there is nothing to write), `proceed_req` will be called or the socket would be |
663 | | * closed if `write_closed` is set. */ |
664 | 0 | self->src_req->write_req.cb(self, self->no_req_streaming); |
665 | |
|
666 | 0 | record_connect_success(self); |
667 | | |
668 | | /* build and submit 200 response */ |
669 | 0 | self->src_req->res.status = 200; |
670 | 0 | h2o_start_response(self->src_req, &self->super); |
671 | 0 | h2o_send(self->src_req, NULL, 0, H2O_SEND_STATE_IN_PROGRESS); |
672 | 0 | } |
673 | | |
674 | | static int tcp_start_connect(struct st_connect_generator_t *self, struct st_server_address_t *server_address) |
675 | 0 | { |
676 | 0 | H2O_PROBE_REQUEST(CONNECT_TCP_START, self->src_req, server_address->sa); |
677 | |
|
678 | 0 | const char *errstr; |
679 | 0 | if ((self->sock = h2o_socket_connect(get_loop(self), server_address->sa, server_address->salen, tcp_on_connect, &errstr)) == |
680 | 0 | NULL) { |
681 | 0 | set_last_error(self, ERROR_CLASS_CONNECT, errstr); |
682 | 0 | return 0; |
683 | 0 | } |
684 | | |
685 | 0 | self->sock->data = self; |
686 | 0 | #if !H2O_USE_LIBUV |
687 | | /* This is the maximum amount of data that will be buffered within userspace. It is hard-coded to 64KB to balance throughput |
688 | | * and latency, and because we do not expect the need to change the value. */ |
689 | 0 | h2o_evloop_socket_set_max_read_size(self->sock, 64 * 1024); |
690 | 0 | #endif |
691 | 0 | self->eyeball_delay.cb = on_connection_attempt_delay_timeout; |
692 | 0 | h2o_timer_link(get_loop(self), self->handler->config.happy_eyeballs.connection_attempt_delay, &self->eyeball_delay); |
693 | |
|
694 | 0 | return 1; |
695 | 0 | } |
696 | | |
697 | | static h2o_iovec_t udp_get_next_chunk(const char *start, size_t len, size_t *to_consume, int *skip) |
698 | 0 | { |
699 | 0 | const uint8_t *bytes = (const uint8_t *)start; |
700 | 0 | const uint8_t *end = bytes + len; |
701 | 0 | uint64_t chunk_type, chunk_length; |
702 | |
|
703 | 0 | chunk_type = ptls_decode_quicint(&bytes, end); |
704 | 0 | if (chunk_type == UINT64_MAX) |
705 | 0 | return h2o_iovec_init(NULL, 0); |
706 | 0 | chunk_length = ptls_decode_quicint(&bytes, end); |
707 | 0 | if (chunk_length == UINT64_MAX) |
708 | 0 | return h2o_iovec_init(NULL, 0); |
709 | | |
710 | | /* chunk is incomplete */ |
711 | 0 | if (end - bytes < chunk_length) |
712 | 0 | return h2o_iovec_init(NULL, 0); |
713 | | |
714 | | /* |
715 | | * https://tools.ietf.org/html/draft-ietf-masque-connect-udp-03#section-6 |
716 | | * CONNECT-UDP Stream Chunks can be used to convey UDP payloads, by |
717 | | * using a CONNECT-UDP Stream Chunk Type of UDP_PACKET (value 0x00). |
718 | | */ |
719 | 0 | *skip = chunk_type != 0; |
720 | 0 | *to_consume = (bytes + chunk_length) - (const uint8_t *)start; |
721 | |
|
722 | 0 | return h2o_iovec_init(bytes, chunk_length); |
723 | 0 | } |
724 | | |
725 | | static void udp_write_core(struct st_connect_generator_t *self, h2o_iovec_t datagram) |
726 | 0 | { |
727 | 0 | const uint8_t *src = (const uint8_t *)datagram.base, *end = src + datagram.len; |
728 | | |
729 | | /* When using RFC 9298, the payload starts with a Context ID; drop anything other than UDP packets. |
730 | | * TODO: propagate error when decoding fails? */ |
731 | 0 | if (!self->udp.is_draft03 && (ptls_decode_quicint(&src, end)) != 0) |
732 | 0 | return; |
733 | | |
734 | 0 | H2O_PROBE_REQUEST(CONNECT_UDP_WRITE, self->src_req, end - src); |
735 | 0 | while (send(h2o_socket_get_fd(self->sock), src, end - src, 0) == -1 && errno == EINTR) |
736 | 0 | ; |
737 | 0 | } |
738 | | |
739 | | static void udp_write_stream_complete_delayed(h2o_timer_t *_timer) |
740 | 0 | { |
741 | 0 | struct st_connect_generator_t *self = H2O_STRUCT_FROM_MEMBER(struct st_connect_generator_t, udp.egress.delayed, _timer); |
742 | |
|
743 | 0 | if (self->write_closed) { |
744 | 0 | close_readwrite(self); |
745 | 0 | return; |
746 | 0 | } |
747 | | |
748 | 0 | self->src_req->proceed_req(self->src_req, NULL); |
749 | 0 | } |
750 | | |
751 | | static void udp_do_write_stream(struct st_connect_generator_t *self, h2o_iovec_t chunk) |
752 | 0 | { |
753 | 0 | int from_buf = 0; |
754 | 0 | size_t off = 0; |
755 | |
|
756 | 0 | reset_io_timeout(self); |
757 | |
|
758 | 0 | if (self->udp.egress.buf->size != 0) { |
759 | 0 | from_buf = 1; |
760 | 0 | if (chunk.len != 0) |
761 | 0 | h2o_buffer_append(&self->udp.egress.buf, chunk.base, chunk.len); |
762 | 0 | chunk.base = self->udp.egress.buf->bytes; |
763 | 0 | chunk.len = self->udp.egress.buf->size; |
764 | 0 | } |
765 | 0 | do { |
766 | 0 | int skip = 0; |
767 | 0 | size_t to_consume; |
768 | 0 | h2o_iovec_t datagram = udp_get_next_chunk(chunk.base + off, chunk.len - off, &to_consume, &skip); |
769 | 0 | if (datagram.base == NULL) |
770 | 0 | break; |
771 | 0 | if (!skip) |
772 | 0 | udp_write_core(self, datagram); |
773 | 0 | off += to_consume; |
774 | 0 | } while (1); |
775 | | |
776 | 0 | if (from_buf) { |
777 | 0 | h2o_buffer_consume(&self->udp.egress.buf, off); |
778 | 0 | } else if (chunk.len != off) { |
779 | 0 | h2o_buffer_append(&self->udp.egress.buf, chunk.base + off, chunk.len - off); |
780 | 0 | } |
781 | |
|
782 | 0 | h2o_timer_link(get_loop(self), 0, &self->udp.egress.delayed); |
783 | 0 | } |
784 | | |
785 | | static int udp_write_stream(void *_self, int is_end_stream) |
786 | 0 | { |
787 | 0 | struct st_connect_generator_t *self = _self; |
788 | 0 | h2o_iovec_t chunk = self->src_req->entity; |
789 | |
|
790 | 0 | assert(!self->write_closed); |
791 | | |
792 | | /* the socket might have been closed tue to a read error */ |
793 | 0 | if (self->socket_closed) |
794 | 0 | return 1; |
795 | | |
796 | 0 | assert(self->sock != NULL && "write_req called before proceed_req is called?"); |
797 | | |
798 | 0 | if (is_end_stream) |
799 | 0 | self->write_closed = 1; |
800 | | |
801 | | /* if the socket is not yet open, buffer input and return */ |
802 | 0 | if (self->sock == NULL) { |
803 | 0 | h2o_buffer_append(&self->udp.egress.buf, chunk.base, chunk.len); |
804 | 0 | return 0; |
805 | 0 | } |
806 | | |
807 | 0 | udp_do_write_stream(self, chunk); |
808 | 0 | return 0; |
809 | 0 | } |
810 | | |
811 | | static void udp_write_datagrams(h2o_req_t *_req, h2o_iovec_t *datagrams, size_t num_datagrams) |
812 | 0 | { |
813 | 0 | struct st_connect_generator_t *self = _req->write_req.ctx; |
814 | |
|
815 | 0 | reset_io_timeout(self); |
816 | |
|
817 | 0 | for (size_t i = 0; i != num_datagrams; ++i) |
818 | 0 | udp_write_core(self, datagrams[i]); |
819 | 0 | } |
820 | | |
821 | | static void udp_on_read(h2o_socket_t *_sock, const char *err) |
822 | 0 | { |
823 | 0 | struct st_connect_generator_t *self = _sock->data; |
824 | 0 | h2o_iovec_t payload = |
825 | 0 | h2o_iovec_init(self->udp.ingress.buf + UDP_CHUNK_OVERHEAD, sizeof(self->udp.ingress.buf) - UDP_CHUNK_OVERHEAD); |
826 | |
|
827 | 0 | if (err != NULL) { |
828 | 0 | close_readwrite(self); |
829 | 0 | return; |
830 | 0 | } |
831 | | |
832 | 0 | { /* read UDP packet, or return */ |
833 | 0 | ssize_t rret; |
834 | 0 | while ((rret = recv(h2o_socket_get_fd(self->sock), payload.base, payload.len, 0)) == -1 && errno == EINTR) |
835 | 0 | ; |
836 | 0 | if (rret == -1) |
837 | 0 | return; |
838 | 0 | payload.len = rret; |
839 | 0 | } |
840 | 0 | H2O_PROBE_REQUEST(CONNECT_UDP_READ, self->src_req, payload.len); |
841 | | |
842 | | /* prepend Context ID (of zero, indicating UDP packet) if RFC 9298 */ |
843 | 0 | if (!self->udp.is_draft03) { |
844 | 0 | *--payload.base = 0; |
845 | 0 | payload.len += 1; |
846 | 0 | } |
847 | | |
848 | | /* forward UDP datagram as is; note that it might be zero-sized */ |
849 | 0 | if (self->src_req->forward_datagram.read_ != NULL) { |
850 | 0 | self->src_req->forward_datagram.read_(self->src_req, &payload, 1); |
851 | 0 | } else { |
852 | 0 | h2o_socket_read_stop(self->sock); |
853 | 0 | h2o_timer_unlink(&self->timeout); |
854 | 0 | { /* prepend Datagram Capsule length */ |
855 | 0 | uint8_t length_buf[8]; |
856 | 0 | size_t length_len = quicly_encodev(length_buf, payload.len) - length_buf; |
857 | 0 | memcpy(payload.base - length_len, length_buf, length_len); |
858 | 0 | payload.base -= length_len; |
859 | 0 | payload.len += length_len; |
860 | 0 | } |
861 | | /* prepend Datagram Capsule Type */ |
862 | 0 | *--payload.base = 0; |
863 | 0 | payload.len += 1; |
864 | 0 | assert(payload.base >= self->udp.ingress.buf); |
865 | 0 | h2o_send(self->src_req, &payload, 1, H2O_SEND_STATE_IN_PROGRESS); |
866 | 0 | } |
867 | 0 | } |
868 | | |
869 | | static void udp_on_proceed(h2o_generator_t *_self, h2o_req_t *req) |
870 | 0 | { |
871 | 0 | struct st_connect_generator_t *self = H2O_STRUCT_FROM_MEMBER(struct st_connect_generator_t, super, _self); |
872 | |
|
873 | 0 | if (self->sock != NULL) { |
874 | 0 | h2o_buffer_consume(&self->sock->input, self->sock->input->size); |
875 | 0 | reset_io_timeout(self); |
876 | 0 | h2o_socket_read_start(self->sock, udp_on_read); |
877 | 0 | } else { |
878 | 0 | self->read_closed = 1; |
879 | 0 | h2o_send(self->src_req, NULL, 0, H2O_SEND_STATE_FINAL); |
880 | 0 | } |
881 | 0 | } |
882 | | |
883 | | static int udp_connect(struct st_connect_generator_t *self, struct st_server_address_t *server_address) |
884 | 0 | { |
885 | 0 | int fd; |
886 | |
|
887 | 0 | assert(self->udp.egress.buf->size == 0); /* the handler does not call `proceed_req` until the connection becomes ready */ |
888 | | |
889 | 0 | H2O_PROBE_REQUEST(CONNECT_UDP_START, self->src_req, server_address->sa); |
890 | | /* connect */ |
891 | 0 | if ((fd = socket(server_address->sa->sa_family, SOCK_DGRAM, 0)) == -1 || |
892 | 0 | connect(fd, server_address->sa, server_address->salen) != 0) { |
893 | 0 | const char *err = h2o_socket_error_conn_fail; |
894 | 0 | if (fd != -1) { |
895 | 0 | err = h2o_socket_get_error_string(errno, err); |
896 | 0 | close(fd); |
897 | 0 | } |
898 | 0 | set_last_error(self, ERROR_CLASS_CONNECT, err); |
899 | 0 | return 0; |
900 | 0 | } |
901 | | |
902 | 0 | stop_eyeballs(self); |
903 | 0 | self->timeout.cb = on_io_timeout; |
904 | 0 | reset_io_timeout(self); |
905 | | |
906 | | /* setup, initiating transfer of early data */ |
907 | | #if H2O_USE_LIBUV |
908 | | self->sock = h2o_uv__poll_create(get_loop(self), fd, (uv_close_cb)free); |
909 | | #else |
910 | 0 | self->sock = h2o_evloop_socket_create(get_loop(self), fd, H2O_SOCKET_FLAG_DONT_READ); |
911 | 0 | #endif |
912 | 0 | assert(self->sock != NULL); |
913 | 0 | self->sock->data = self; |
914 | 0 | self->src_req->write_req.cb = udp_write_stream; |
915 | 0 | self->src_req->forward_datagram.write_ = udp_write_datagrams; |
916 | 0 | self->src_req->write_req.ctx = self; |
917 | |
|
918 | 0 | record_connect_success(self); |
919 | | |
920 | | /* build and submit success */ |
921 | 0 | if (self->src_req->version < 0x200 && !self->udp.is_draft03) { |
922 | 0 | assert(self->src_req->upgrade.base != NULL); |
923 | 0 | self->src_req->res.status = 101; |
924 | 0 | self->src_req->res.reason = "Switching Protocols"; |
925 | 0 | h2o_add_header(&self->src_req->pool, &self->src_req->res.headers, H2O_TOKEN_UPGRADE, NULL, H2O_STRLIT("connect-udp")); |
926 | 0 | } else { |
927 | 0 | self->src_req->res.status = 200; |
928 | 0 | } |
929 | 0 | if (!self->udp.is_draft03) |
930 | 0 | h2o_add_header_by_str(&self->src_req->pool, &self->src_req->res.headers, H2O_STRLIT("capsule-protocol"), 0, NULL, |
931 | 0 | H2O_STRLIT("?1")); |
932 | 0 | h2o_start_response(self->src_req, &self->super); |
933 | 0 | h2o_send(self->src_req, NULL, 0, H2O_SEND_STATE_IN_PROGRESS); |
934 | | |
935 | | /* write any data if provided, or just call the proceed_req callback */ |
936 | 0 | self->src_req->write_req.cb(self, self->no_req_streaming); |
937 | |
|
938 | 0 | return 1; |
939 | 0 | } |
940 | | |
941 | | static void on_stop(h2o_generator_t *_self, h2o_req_t *req) |
942 | 0 | { |
943 | 0 | struct st_connect_generator_t *self = H2O_STRUCT_FROM_MEMBER(struct st_connect_generator_t, super, _self); |
944 | 0 | dispose_generator(self); |
945 | 0 | } |
946 | | |
947 | | static void on_generator_dispose(void *_self) |
948 | 0 | { |
949 | 0 | struct st_connect_generator_t *self = _self; |
950 | 0 | H2O_PROBE_REQUEST0(CONNECT_DISPOSE, self->src_req); |
951 | 0 | dispose_generator(self); |
952 | 0 | } |
953 | | |
954 | | /** |
955 | | * expects "/host/port/" as input, where the preceding slash is optional |
956 | | */ |
957 | | static int masque_decode_hostport(h2o_mem_pool_t *pool, const char *_src, size_t _len, h2o_iovec_t *host, uint16_t *port) |
958 | 0 | { |
959 | 0 | char *src = (char *)_src; /* h2o_strtosizefwd takes non-const arg, so ... */ |
960 | 0 | const char *end = src + _len; |
961 | |
|
962 | 0 | if (src < end && src[0] == '/') |
963 | 0 | ++src; |
964 | |
|
965 | 0 | { /* extract host */ |
966 | 0 | size_t host_len; |
967 | 0 | if ((host_len = h2o_strstr(src, end - src, H2O_STRLIT("/"))) == SIZE_MAX || host_len == 0) |
968 | 0 | return 0; |
969 | 0 | if ((*host = h2o_uri_unescape(pool, src, host_len)).base == NULL) |
970 | 0 | return 0; |
971 | 0 | src += host_len + 1; |
972 | 0 | } |
973 | | |
974 | 0 | { /* parse port */ |
975 | 0 | size_t v; |
976 | 0 | if ((v = h2o_strtosizefwd(&src, end - src)) >= 65535) |
977 | 0 | return 0; |
978 | 0 | if (src == end || *src != '/') |
979 | 0 | return 0; |
980 | 0 | *port = (uint16_t)v; |
981 | 0 | } |
982 | | |
983 | 0 | return 1; |
984 | 0 | } |
985 | | |
986 | | static int on_req_core(struct st_connect_handler_t *handler, h2o_req_t *req, h2o_iovec_t host, uint16_t port, int is_tcp, |
987 | | int is_masque_draft03) |
988 | 0 | { |
989 | 0 | struct st_connect_generator_t *self; |
990 | 0 | size_t sizeof_self = offsetof(struct st_connect_generator_t, tcp) + (is_tcp ? sizeof(self->tcp) : sizeof(self->udp)); |
991 | 0 | self = h2o_mem_alloc_shared(&req->pool, sizeof_self, on_generator_dispose); |
992 | 0 | memset(self, 0, sizeof_self); |
993 | 0 | self->super.stop = on_stop; |
994 | 0 | self->handler = handler; |
995 | 0 | self->src_req = req; |
996 | 0 | self->timeout.cb = on_connect_timeout; |
997 | 0 | if (is_tcp) { |
998 | 0 | self->is_tcp = 1; |
999 | 0 | self->super.proceed = tcp_on_proceed; |
1000 | 0 | h2o_buffer_init(&self->tcp.sendbuf, &h2o_socket_buffer_prototype); |
1001 | 0 | } else { |
1002 | 0 | self->super.proceed = udp_on_proceed; |
1003 | 0 | h2o_buffer_init(&self->udp.egress.buf, &h2o_socket_buffer_prototype); |
1004 | 0 | self->udp.egress.delayed = (h2o_timer_t){.cb = udp_write_stream_complete_delayed}; |
1005 | 0 | self->udp.is_draft03 = is_masque_draft03; |
1006 | 0 | } |
1007 | 0 | h2o_timer_link(get_loop(self), handler->config.connect_timeout, &self->timeout); |
1008 | | |
1009 | | /* setup write_req now, so that the protocol handler would not provide additional data until we call `proceed_req` */ |
1010 | 0 | assert(req->entity.base != NULL && "CONNECT must indicate existence of payload"); |
1011 | 0 | self->src_req->write_req.cb = is_tcp ? tcp_write : udp_write_stream; |
1012 | 0 | self->src_req->write_req.ctx = self; |
1013 | 0 | if (self->src_req->proceed_req == NULL) |
1014 | 0 | self->no_req_streaming = 1; |
1015 | |
|
1016 | 0 | char port_str[sizeof(H2O_UINT16_LONGEST_STR)]; |
1017 | 0 | int port_strlen = sprintf(port_str, "%" PRIu16, port); |
1018 | |
|
1019 | 0 | self->getaddr_req.v6 = h2o_hostinfo_getaddr( |
1020 | 0 | &self->src_req->conn->ctx->receivers.hostinfo_getaddr, host, h2o_iovec_init(port_str, port_strlen), AF_INET6, |
1021 | 0 | is_tcp ? SOCK_STREAM : SOCK_DGRAM, is_tcp ? IPPROTO_TCP : IPPROTO_UDP, AI_ADDRCONFIG | AI_NUMERICSERV, on_getaddr, self); |
1022 | 0 | self->getaddr_req.v4 = h2o_hostinfo_getaddr( |
1023 | 0 | &self->src_req->conn->ctx->receivers.hostinfo_getaddr, host, h2o_iovec_init(port_str, port_strlen), AF_INET, |
1024 | 0 | is_tcp ? SOCK_STREAM : SOCK_DGRAM, is_tcp ? IPPROTO_TCP : IPPROTO_UDP, AI_ADDRCONFIG | AI_NUMERICSERV, on_getaddr, self); |
1025 | |
|
1026 | 0 | return 0; |
1027 | 0 | } |
1028 | | |
1029 | | static int on_req_classic_connect(h2o_handler_t *_handler, h2o_req_t *req) |
1030 | 0 | { |
1031 | 0 | struct st_connect_handler_t *handler = (void *)_handler; |
1032 | 0 | h2o_iovec_t host; |
1033 | 0 | uint16_t port; |
1034 | 0 | int is_tcp; |
1035 | |
|
1036 | 0 | if (req->upgrade.base != NULL) { |
1037 | 0 | return -1; |
1038 | 0 | } else if (h2o_memis(req->method.base, req->method.len, H2O_STRLIT("CONNECT"))) { |
1039 | | /* old-style CONNECT */ |
1040 | 0 | is_tcp = 1; |
1041 | 0 | } else if (h2o_memis(req->method.base, req->method.len, H2O_STRLIT("CONNECT-UDP"))) { |
1042 | | /* masque (draft 03); host and port are stored the same way as ordinary CONNECT |
1043 | | * TODO remove code once we drop support for draft-03 */ |
1044 | 0 | if (!handler->config.support_masque_draft_03) { |
1045 | 0 | h2o_send_error_405(req, "Method Not Allowed", "Method Not Allowed", H2O_SEND_ERROR_KEEP_HEADERS); |
1046 | 0 | return 0; |
1047 | 0 | } |
1048 | 0 | is_tcp = 0; |
1049 | 0 | } else { |
1050 | | /* it is not the task of this handler to handle non-CONNECT requests */ |
1051 | 0 | return -1; |
1052 | 0 | } |
1053 | | |
1054 | | /* parse host and port from authority, unless it is handled above in the case of extended connect */ |
1055 | 0 | if (h2o_url_parse_hostport(req->authority.base, req->authority.len, &host, &port) == NULL || port == 0 || port == 65535) { |
1056 | 0 | record_error(handler, req, NULL, "http_request_error", "invalid host:port", NULL); |
1057 | 0 | h2o_send_error_400(req, "Bad Request", "Bad Request", H2O_SEND_ERROR_KEEP_HEADERS); |
1058 | 0 | return 0; |
1059 | 0 | } |
1060 | | |
1061 | 0 | return on_req_core((void *)handler, req, host, port, is_tcp, 1); |
1062 | 0 | } |
1063 | | |
1064 | | /** |
1065 | | * handles RFC9298 requests |
1066 | | */ |
1067 | | static int on_req_connect_udp(h2o_handler_t *_handler, h2o_req_t *req) |
1068 | 0 | { |
1069 | 0 | struct st_connect_handler_t *handler = (void *)_handler; |
1070 | 0 | h2o_iovec_t host; |
1071 | 0 | uint16_t port; |
1072 | | |
1073 | | /* reject requests wo. upgrade: connect-udp */ |
1074 | 0 | if (!(req->upgrade.base != NULL && h2o_lcstris(req->upgrade.base, req->upgrade.len, H2O_STRLIT("connect-udp")))) |
1075 | 0 | return -1; |
1076 | | |
1077 | | /* check method */ |
1078 | 0 | if (!(req->version < 0x200 ? h2o_memis(req->method.base, req->method.len, H2O_STRLIT("GET")) |
1079 | 0 | : h2o_memis(req->method.base, req->method.len, H2O_STRLIT("CONNECT")))) |
1080 | 0 | return -1; |
1081 | | |
1082 | | /* masque (RFC 9298); parse host/port */ |
1083 | 0 | if (!masque_decode_hostport(&req->pool, req->path_normalized.base + req->pathconf->path.len, |
1084 | 0 | req->path_normalized.len - req->pathconf->path.len, &host, &port)) { |
1085 | 0 | record_error(handler, req, NULL, "http_request_error", "invalid URI", NULL); |
1086 | 0 | h2o_send_error_400(req, "Bad Request", "Bad Request", H2O_SEND_ERROR_KEEP_HEADERS); |
1087 | 0 | return 0; |
1088 | 0 | } |
1089 | | |
1090 | 0 | return on_req_core((void *)handler, req, host, port, 0, 0); |
1091 | 0 | } |
1092 | | |
1093 | | static void do_register(h2o_pathconf_t *pathconf, h2o_proxy_config_vars_t *config, h2o_connect_acl_entry_t *acl_entries, |
1094 | | size_t num_acl_entries, int (*on_req)(struct st_h2o_handler_t *self, h2o_req_t *req)) |
1095 | 0 | { |
1096 | 0 | assert(config->max_buffer_size != 0); |
1097 | | |
1098 | 0 | struct st_connect_handler_t *self = (void *)h2o_create_handler(pathconf, offsetof(struct st_connect_handler_t, acl.entries) + |
1099 | 0 | sizeof(*self->acl.entries) * num_acl_entries); |
1100 | |
|
1101 | 0 | self->super.on_req = on_req; |
1102 | 0 | self->super.supports_request_streaming = 1; |
1103 | 0 | self->config = *config; |
1104 | 0 | self->acl.count = num_acl_entries; |
1105 | 0 | memcpy(self->acl.entries, acl_entries, sizeof(self->acl.entries[0]) * num_acl_entries); |
1106 | 0 | } |
1107 | | |
1108 | | void h2o_connect_register(h2o_pathconf_t *pathconf, h2o_proxy_config_vars_t *config, h2o_connect_acl_entry_t *acl_entries, |
1109 | | size_t num_acl_entries) |
1110 | 0 | { |
1111 | 0 | do_register(pathconf, config, acl_entries, num_acl_entries, on_req_classic_connect); |
1112 | 0 | } |
1113 | | |
1114 | | void h2o_connect_udp_register(h2o_pathconf_t *pathconf, h2o_proxy_config_vars_t *config, h2o_connect_acl_entry_t *acl_entries, |
1115 | | size_t num_acl_entries) |
1116 | 0 | { |
1117 | 0 | do_register(pathconf, config, acl_entries, num_acl_entries, on_req_connect_udp); |
1118 | 0 | } |
1119 | | |
1120 | | const char *h2o_connect_parse_acl(h2o_connect_acl_entry_t *output, const char *input) |
1121 | 0 | { |
1122 | | /* type */ |
1123 | 0 | switch (input[0]) { |
1124 | 0 | case '+': |
1125 | 0 | output->allow_ = 1; |
1126 | 0 | break; |
1127 | 0 | case '-': |
1128 | 0 | output->allow_ = 0; |
1129 | 0 | break; |
1130 | 0 | default: |
1131 | 0 | return "ACL entry must begin with + or -"; |
1132 | 0 | } |
1133 | | |
1134 | | /* extract address, port */ |
1135 | 0 | h2o_iovec_t host_vec; |
1136 | 0 | uint16_t port; |
1137 | 0 | const char *slash_at; |
1138 | 0 | if ((slash_at = h2o_url_parse_hostport(input + 1, strlen(input + 1), &host_vec, &port)) == NULL) |
1139 | 0 | goto GenericParseError; |
1140 | 0 | char *host = alloca(host_vec.len + 1); |
1141 | 0 | memcpy(host, host_vec.base, host_vec.len); |
1142 | 0 | host[host_vec.len] = '\0'; |
1143 | | |
1144 | | /* parse netmask (or addr_mask is set to zero to indicate that mask was not specified) */ |
1145 | 0 | if (*slash_at != '\0') { |
1146 | 0 | if (*slash_at != '/') |
1147 | 0 | goto GenericParseError; |
1148 | 0 | if (sscanf(slash_at + 1, "%zu", &output->addr_mask) != 1 || output->addr_mask == 0) |
1149 | 0 | return "invalid address mask"; |
1150 | 0 | } else { |
1151 | 0 | output->addr_mask = 0; |
1152 | 0 | } |
1153 | | |
1154 | | /* parse address */ |
1155 | 0 | struct in_addr v4addr; |
1156 | 0 | struct in6_addr v6addr; |
1157 | 0 | if (strcmp(host, "*") == 0) { |
1158 | 0 | output->addr_family = H2O_CONNECT_ACL_ADDRESS_ANY; |
1159 | 0 | if (output->addr_mask != 0) |
1160 | 0 | return "wildcard address (*) cannot have a netmask"; |
1161 | 0 | } else if (inet_pton(AF_INET, host, &v4addr) == 1) { |
1162 | 0 | output->addr_family = H2O_CONNECT_ACL_ADDRESS_V4; |
1163 | 0 | if (output->addr_mask == 0) { |
1164 | 0 | output->addr_mask = 32; |
1165 | 0 | } else if (output->addr_mask > 32) { |
1166 | 0 | return "invalid address mask"; |
1167 | 0 | } |
1168 | 0 | output->addr.v4 = ntohl(v4addr.s_addr) & TO_BITMASK(uint32_t, output->addr_mask); |
1169 | 0 | } else if (inet_pton(AF_INET6, host, &v6addr) == 1) { |
1170 | 0 | output->addr_family = H2O_CONNECT_ACL_ADDRESS_V6; |
1171 | 0 | if (output->addr_mask == 0) { |
1172 | 0 | output->addr_mask = 128; |
1173 | 0 | } else if (output->addr_mask > 128) { |
1174 | 0 | return "invalid address mask"; |
1175 | 0 | } |
1176 | 0 | size_t i; |
1177 | 0 | for (i = 0; i < output->addr_mask / 8; ++i) |
1178 | 0 | output->addr.v6[i] = v6addr.s6_addr[i]; |
1179 | 0 | if (output->addr_mask % 8 != 0) |
1180 | 0 | output->addr.v6[i] = v6addr.s6_addr[i] & TO_BITMASK(uint8_t, output->addr_mask % 8); |
1181 | 0 | for (++i; i < PTLS_ELEMENTSOF(output->addr.v6); ++i) |
1182 | 0 | output->addr.v6[i] = 0; |
1183 | 0 | } else { |
1184 | 0 | return "failed to parse address"; |
1185 | 0 | } |
1186 | | |
1187 | | /* set port (for whatever reason, `h2o_url_parse_hostport` sets port to 65535 when not specified, convert that to zero) */ |
1188 | 0 | output->port = port == 65535 ? 0 : port; |
1189 | |
|
1190 | 0 | return NULL; |
1191 | | |
1192 | 0 | GenericParseError: |
1193 | 0 | return "failed to parse input, expected format is: [+-]address(?::port|)(?:/netmask|)"; |
1194 | 0 | } |
1195 | | |
1196 | | int h2o_connect_lookup_acl(h2o_connect_acl_entry_t *acl_entries, size_t num_acl_entries, struct sockaddr *target) |
1197 | 0 | { |
1198 | 0 | uint32_t target_v4addr = 0; |
1199 | 0 | uint16_t target_port; |
1200 | | |
1201 | | /* reject anything other than v4/v6, as well as converting the values to native format */ |
1202 | 0 | switch (target->sa_family) { |
1203 | 0 | case AF_INET: { |
1204 | 0 | struct sockaddr_in *sin = (void *)target; |
1205 | 0 | target_v4addr = ntohl(sin->sin_addr.s_addr); |
1206 | 0 | target_port = ntohs(sin->sin_port); |
1207 | 0 | } break; |
1208 | 0 | case AF_INET6: |
1209 | 0 | target_port = htons(((struct sockaddr_in6 *)target)->sin6_port); |
1210 | 0 | break; |
1211 | 0 | default: |
1212 | 0 | return 0; |
1213 | 0 | } |
1214 | | |
1215 | | /* check each ACL entry */ |
1216 | 0 | for (size_t i = 0; i != num_acl_entries; ++i) { |
1217 | 0 | h2o_connect_acl_entry_t *entry = acl_entries + i; |
1218 | | /* check port */ |
1219 | 0 | if (entry->port != 0 && entry->port != target_port) |
1220 | 0 | goto Next; |
1221 | | /* check address */ |
1222 | 0 | switch (entry->addr_family) { |
1223 | 0 | case H2O_CONNECT_ACL_ADDRESS_ANY: |
1224 | 0 | break; |
1225 | 0 | case H2O_CONNECT_ACL_ADDRESS_V4: { |
1226 | 0 | if (target->sa_family != AF_INET) |
1227 | 0 | goto Next; |
1228 | 0 | if (entry->addr.v4 != (target_v4addr & TO_BITMASK(uint32_t, entry->addr_mask))) |
1229 | 0 | goto Next; |
1230 | 0 | } break; |
1231 | 0 | case H2O_CONNECT_ACL_ADDRESS_V6: { |
1232 | 0 | if (target->sa_family != AF_INET6) |
1233 | 0 | continue; |
1234 | 0 | uint8_t *target_v6addr = ((struct sockaddr_in6 *)target)->sin6_addr.s6_addr; |
1235 | 0 | size_t i; |
1236 | 0 | for (i = 0; i < entry->addr_mask / 8; ++i) |
1237 | 0 | if (entry->addr.v6[i] != target_v6addr[i]) |
1238 | 0 | goto Next; |
1239 | 0 | if (entry->addr_mask % 8 != 0 && entry->addr.v6[i] != (target_v6addr[i] & TO_BITMASK(uint8_t, entry->addr_mask % 8))) |
1240 | 0 | goto Next; |
1241 | 0 | } break; |
1242 | 0 | } |
1243 | | /* match */ |
1244 | 0 | return entry->allow_; |
1245 | 0 | Next:; |
1246 | 0 | } |
1247 | | |
1248 | | /* default rule is deny */ |
1249 | 0 | return 0; |
1250 | 0 | } |