Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ static const struct Keyword listener_stanza_grammar[] = {
.keyword="source",
.parse_arg=(int(*)(void *, const char *))accept_listener_source_address,
},
{
.keyword="embed",
.parse_arg=(int(*)(void *, const char *))accept_listener_embed_address,
},
{
.keyword="access_log",
.create=(void *(*)())new_logger_builder,
Expand Down
29 changes: 29 additions & 0 deletions src/connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,35 @@ initiate_server_connect(struct Connection *con, struct ev_loop *loop) {
abort_connection(con);
return;
}
} else if (con->listener->embed_address
&& con->client.addr.ss_family == AF_INET
&& con->server.addr.ss_family == AF_INET6) {
struct sockaddr_in6 embedded_source;
#ifdef IP_FREEBIND
int on = 1;
int result = setsockopt(sockfd, SOL_IP, IP_FREEBIND, &on, sizeof(on));
if (result < 0) {
warn("setsockopt IP_FREEBIND failed: %s", strerror(errno));
// May not be necessary if user has set sysctl net.ipv6.ip_nonlocal_bind
}
#else
int result = -EPERM;
#endif

memcpy(&embedded_source,
address_sa(con->listener->embed_address),
sizeof(embedded_source));
memcpy(&(embedded_source.sin6_addr.s6_addr[12]),
&((struct sockaddr_in*)(&con->client.addr))->sin_addr, 4);
// XXX: maybe optionally the source port in bits 80-95

result = bind(sockfd, &embedded_source, sizeof(embedded_source));
if (result < 0) {
err("bind failed: %s", strerror(errno));
close(sockfd);
abort_connection(con);
return;
}
} else if (con->listener->source_address) {
int on = 1;
int result = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
Expand Down
45 changes: 45 additions & 0 deletions src/listener.c
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,10 @@ listener_update(struct Listener *existing_listener, struct Listener *new_listene
existing_listener->source_address = new_listener->source_address;
new_listener->source_address = NULL;

free(existing_listener->embed_address);
existing_listener->embed_address = new_listener->embed_address;
new_listener->embed_address = NULL;

existing_listener->protocol = new_listener->protocol;

free(existing_listener->table_name);
Expand Down Expand Up @@ -212,6 +216,7 @@ new_listener() {
listener->address = NULL;
listener->fallback_address = NULL;
listener->source_address = NULL;
listener->embed_address = NULL;
listener->protocol = tls_protocol;
listener->table_name = NULL;
listener->access_log = NULL;
Expand Down Expand Up @@ -406,6 +411,40 @@ accept_listener_source_address(struct Listener *listener, const char *source) {
return 1;
}

int
accept_listener_embed_address(struct Listener *listener, const char *embed) {
if (listener->embed_address != NULL) {
err("Duplicate embed address: %s", embed);
return 0;
}

listener->embed_address = new_address(embed);
if (listener->embed_address == NULL) {
err("Unable to parse embed address: %s", embed);
return 0;
}
if (!address_is_sockaddr(listener->embed_address)) {
err("Only embed socket addresses permitted");
free(listener->embed_address);
listener->embed_address = NULL;
return 0;
}
if (address_sa(listener->embed_address)->sa_family != AF_INET6) {
err("Embed address must be IPv6 prefix");
free(listener->embed_address);
listener->embed_address = NULL;
return 0;
}
if (address_port(listener->embed_address) != 0) {
err("Port on embed address not permitted");
free(listener->embed_address);
listener->embed_address = NULL;
return 0;
}

return 1;
}

int
accept_listener_bad_request_action(struct Listener *listener, const char *action) {
if (strncmp("log", action, strlen(action)) == 0) {
Expand Down Expand Up @@ -707,6 +746,11 @@ print_listener_config(FILE *file, const struct Listener *listener) {
display_address(listener->source_address,
address, sizeof(address)));

if (listener->embed_address)
fprintf(file, "\tembed %s\n",
display_address(listener->embed_address,
address, sizeof(address)));

if (listener->reuseport)
fprintf(file, "\treuseport on\n");

Expand All @@ -732,6 +776,7 @@ free_listener(struct Listener *listener) {
free(listener->address);
free(listener->fallback_address);
free(listener->source_address);
free(listener->embed_address);
free(listener->table_name);

table_ref_put(listener->table);
Expand Down
3 changes: 2 additions & 1 deletion src/listener.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ SLIST_HEAD(Listener_head, Listener);

struct Listener {
/* Configuration fields */
struct Address *address, *fallback_address, *source_address;
struct Address *address, *fallback_address, *source_address, *embed_address;
const struct Protocol *protocol;
char *table_name;
struct Logger *access_log;
Expand All @@ -57,6 +57,7 @@ int accept_listener_arg(struct Listener *, const char *);
int accept_listener_table_name(struct Listener *, const char *);
int accept_listener_fallback_address(struct Listener *, const char *);
int accept_listener_source_address(struct Listener *, const char *);
int accept_listener_embed_address(struct Listener *, const char *);
int accept_listener_protocol(struct Listener *, const char *);
int accept_listener_reuseport(struct Listener *, const char *);
int accept_listener_ipv6_v6only(struct Listener *, const char *);
Expand Down