Skip to content

Commit

Permalink
Merge pull request h2o#3360 from deweerdt/ipv6f
Browse files Browse the repository at this point in the history
http/3 quic: fix inter node forwarding for mismatched address families
  • Loading branch information
kazuho authored Mar 4, 2024
2 parents f5765a8 + 731f011 commit 579135a
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 13 deletions.
33 changes: 24 additions & 9 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,10 @@ struct listener_config_t {
* QPACK settings
*/
h2o_http3_qpack_context_t qpack;
/**
* the matching ipv6 listener for an ipv4 listener and vice versa
*/
struct listener_config_t *sibling;
} quic;
/**
* SO_SNDBUF, SO_RCVBUF values to be set (or 0 to use default)
Expand Down Expand Up @@ -2789,6 +2793,7 @@ static int on_config_listen_element(h2o_configurator_command_t *cmd, h2o_configu
}
if ((res = resolve_address(cmd, node, SOCK_DGRAM, IPPROTO_UDP, hostname, servname)) == NULL)
return -1;
struct listener_config_t *siblings[2] = {NULL, NULL};
for (ai = res; ai != NULL; ai = ai->ai_next) {
struct listener_config_t *listener = find_listener(ai->ai_addr, ai->ai_addrlen, 1);
int listener_is_new = 0;
Expand Down Expand Up @@ -2818,6 +2823,10 @@ static int on_config_listen_element(h2o_configurator_command_t *cmd, h2o_configu
quic->generate_resumption_token = &quic_resumption_token_generator;
quic->async_handshake = &async_nb_quic_handler;
listener = add_listener(fd, ai->ai_addr, ai->ai_addrlen, ctx->hostconf == NULL, 0, 0, 0);
if (ai->ai_family == AF_INET)
siblings[0] = listener;
else if (ai->ai_family == AF_INET6)
siblings[1] = listener;
listener->quic.ctx = quic;
if (quic_node != NULL) {
yoml_t **retry_node, **sndbuf, **rcvbuf, **amp_limit, **qpack_encoder_table_capacity, **max_streams_bidi,
Expand Down Expand Up @@ -2899,6 +2908,10 @@ static int on_config_listen_element(h2o_configurator_command_t *cmd, h2o_configu
if (listener->hosts != NULL && ctx->hostconf != NULL)
h2o_append_to_null_terminated_list((void *)&listener->hosts, ctx->hostconf);
}
if (siblings[0] != NULL && siblings[1] != NULL) {
siblings[0]->quic.sibling = siblings[1];
siblings[1]->quic.sibling = siblings[0];
}
freeaddrinfo(res);

} else {
Expand Down Expand Up @@ -3576,18 +3589,10 @@ static void setup_signal_handlers(void)
#endif
}

struct st_h2o_quic_forwarded_t {
union {
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
} srcaddr, destaddr;
int is_v6 : 1;
};

/* FIXME forward destaddr */
/* The format:
* type: 0b10000000 (1 byte)
* version: 0x91917000 (4 bytes)
* version: 0x91c17000 (4 bytes)
* destaddr: 1 or 7 or 19 bytes (UNSPEC, v4, v6)
* srcaddr: same as above
* ttl: 1 byte
Expand Down Expand Up @@ -3790,6 +3795,16 @@ static int rewrite_forwarded_quic_datagram(h2o_quic_ctx_t *h3ctx, struct msghdr
return 1;
break;
}
if (encapsulated.destaddr.sa.sa_family != h3ctx->sock.addr.ss_family) {
struct listener_config_t *listener_config = conf.listeners[lctx->listener_index];
if (listener_config->quic.sibling != NULL) {
int fd = listener_config->quic.sibling->quic.thread_fds[h3ctx->next_cid.thread_id];
write(fd, msg->msg_iov[0].iov_base, msg->msg_iov[0].iov_len);
} else {
/* drop packet */
}
return 0;
}

/* update */
msg->msg_iov[0].iov_base += encapsulated.offset;
Expand Down
11 changes: 7 additions & 4 deletions t/40http3-forward.t
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ plan skip_all => "macOS has issues https://twitter.com/kazuho/status/12980731105
my $quic_port = empty_port({ host => "0.0.0.0", proto => "udp" });

# start server1 at 0.0.0.0, check that it is up
my $server1 = spawn("0.0.0.0", 1);
my $server1 = spawn("*", 1);
is do {my $fh = fetch(""); local $/; join "", <$fh> }, "server=1", "server1 is up";

# initiate the slow request
Expand Down Expand Up @@ -66,19 +66,22 @@ done_testing;

sub spawn {
my ($listen_ip, $server_id) = @_;
my $host_directive = "";
if ($listen_ip ne "*") {
$host_directive = "\n host: $listen_ip";
}
my $conf = {opts => [qw(-m worker)], conf => <<"EOT"};
num-threads: 1
listen:
type: quic
host: $listen_ip
type: quic$host_directive
port: $quic_port
ssl:
key-file: examples/h2o/server.key
certificate-file: examples/h2o/server.crt
quic-nodes:
self: $server_id
mapping:
1: "127.0.0.2:$quic_port" # server1 can be reached at 127.0.0.2 too
1: "[::1]:$quic_port" # server1 can be reached over ipv6 as well
2: "127.0.0.1:$quic_port"
ssl-session-resumption:
mode: ticket
Expand Down

0 comments on commit 579135a

Please sign in to comment.