Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement ECS address override feature #1168

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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
10 changes: 10 additions & 0 deletions doc/unbound.conf.5.in
Original file line number Diff line number Diff line change
Expand Up @@ -2622,6 +2622,16 @@ the client query). If enabled, the address check is skipped when the client
query contains an ECS record. And the lookup in the regular cache is skipped.
Default is no.
.TP
.B client\-subnet\-address\-override\-ipv4: \fI<IPv4 subnet>\fR
Override client source address in queries to the provided IPv4 subnet. Only
applies if the query includes the ECS option and the ECS address family is IPv4.
Default is to use the actual IPv4 subnet of the original client query.
.TP
.B client\-subnet\-address\-override\-ipv6: \fI<IPv6 subnet>\fR
Override client source address in queries to the provided IPv6 subnet. Only
applies if the query includes the ECS option and the ECS address family is IPv6.
Default is to use the actual IPv6 subnet of the original client query.
.TP
.B max\-client\-subnet\-ipv6: \fI<number>\fR
Specifies the maximum prefix length of the client source address we are willing
to expose to third parties for IPv6. Defaults to 56.
Expand Down
45 changes: 40 additions & 5 deletions edns-subnet/subnetmod.c
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,31 @@ subnetmod_init(struct module_env *env, int id)
env->modinfo[id] = NULL;
return 0;
}
/* Copy address override settings */
if(env->cfg->client_subnet_address_override_ipv4) {
struct sockaddr_storage *addr = &sn_env->address_override_v4;
char *ipstr = env->cfg->client_subnet_address_override_ipv4;
socklen_t len = 0;
if(!ipstrtoaddr(ipstr, 0, addr, &len) || addr->ss_family != AF_INET) {
log_err("subnetcache: error parsing ipv4 address override: '%s'", ipstr);
free(sn_env);
env->modinfo[id] = NULL;
return 0;
}
sn_env->do_address_override_v4 = 1;
}
if(env->cfg->client_subnet_address_override_ipv6) {
struct sockaddr_storage *addr = &sn_env->address_override_v6;
char *ipstr = env->cfg->client_subnet_address_override_ipv6;
socklen_t len = 0;
if(!ipstrtoaddr(ipstr, 0, addr, &len) || addr->ss_family != AF_INET6) {
log_err("subnetcache: error parsing ipv6 address override: '%s'", ipstr);
free(sn_env);
env->modinfo[id] = NULL;
return 0;
}
sn_env->do_address_override_v6 = 1;
}

verbose(VERB_QUERY, "subnetcache: option registered (%d)",
env->cfg->client_subnet_opcode);
Expand Down Expand Up @@ -684,15 +709,20 @@ parse_subnet_option(struct edns_option* ecs_option, struct ecs_data* ecs)

void
subnet_option_from_ss(struct sockaddr_storage *ss, struct ecs_data* ecs,
struct config_file* cfg)
struct config_file* cfg, const struct subnet_env* sne)
{
void* sinaddr;

/* Construct subnet option from original query */
if(((struct sockaddr_in*)ss)->sin_family == AF_INET) {
ecs->subnet_source_mask = cfg->max_client_subnet_ipv4;
ecs->subnet_addr_fam = EDNSSUBNET_ADDRFAM_IP4;
sinaddr = &((struct sockaddr_in*)ss)->sin_addr;
if (sne->do_address_override_v4) {
sinaddr = &((struct sockaddr_in*)
(&sne->address_override_v4))->sin_addr;
} else {
sinaddr = &((struct sockaddr_in*)ss)->sin_addr;
}
if (!copy_clear( ecs->subnet_addr, INET6_SIZE,
(uint8_t *)sinaddr, INET_SIZE,
ecs->subnet_source_mask)) {
Expand All @@ -703,7 +733,12 @@ subnet_option_from_ss(struct sockaddr_storage *ss, struct ecs_data* ecs,
else {
ecs->subnet_source_mask = cfg->max_client_subnet_ipv6;
ecs->subnet_addr_fam = EDNSSUBNET_ADDRFAM_IP6;
sinaddr = &((struct sockaddr_in6*)ss)->sin6_addr;
if (sne->do_address_override_v6) {
sinaddr = &((struct sockaddr_in6*)
(&sne->address_override_v6))->sin6_addr;
} else {
sinaddr = &((struct sockaddr_in6*)ss)->sin6_addr;
}
if (!copy_clear( ecs->subnet_addr, INET6_SIZE,
(uint8_t *)sinaddr, INET6_SIZE,
ecs->subnet_source_mask)) {
Expand Down Expand Up @@ -839,12 +874,12 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event,
else if(qstate->mesh_info->reply_list) {
subnet_option_from_ss(
&qstate->mesh_info->reply_list->query_reply.client_addr,
&sq->ecs_client_in, qstate->env->cfg);
&sq->ecs_client_in, qstate->env->cfg, sne);
}
else if(qstate->client_addr.ss_family != AF_UNSPEC) {
subnet_option_from_ss(
&qstate->client_addr,
&sq->ecs_client_in, qstate->env->cfg);
&sq->ecs_client_in, qstate->env->cfg, sne);
}

if(sq->ecs_client_in.subnet_validdata == 0) {
Expand Down
10 changes: 9 additions & 1 deletion edns-subnet/subnetmod.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,14 @@ struct subnet_env {
struct slabhash* subnet_msg_cache;
/** access control, which upstream servers we send client address */
struct ecs_whitelist* whitelist;
/** whether to override client source address for IPv4 */
int do_address_override_v4;
/** whether to override client source address for IPv6 */
int do_address_override_v6;
/** overide client source address value for IPv4 */
struct sockaddr_storage address_override_v4;
/** overide client source address value for IPv6 */
struct sockaddr_storage address_override_v6;
/** allocation service */
struct alloc_cache alloc;
lock_rw_type biglock;
Expand Down Expand Up @@ -159,5 +167,5 @@ void subnet_ecs_opt_list_append(struct ecs_data* ecs, struct edns_option** list,

/** Create ecs_data from the sockaddr_storage information. */
void subnet_option_from_ss(struct sockaddr_storage *ss, struct ecs_data* ecs,
struct config_file* cfg);
struct config_file* cfg, const struct subnet_env* sne);
#endif /* SUBNETMOD_H */
6 changes: 6 additions & 0 deletions util/config_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,8 @@ config_create(void)
cfg->client_subnet = NULL;
cfg->client_subnet_zone = NULL;
cfg->client_subnet_opcode = LDNS_EDNS_CLIENT_SUBNET;
cfg->client_subnet_address_override_ipv4 = NULL;
cfg->client_subnet_address_override_ipv6 = NULL;
cfg->client_subnet_always_forward = 0;
cfg->max_client_subnet_ipv4 = 24;
cfg->max_client_subnet_ipv6 = 56;
Expand Down Expand Up @@ -1255,6 +1257,8 @@ config_get_option(struct config_file* cfg, const char* opt,
#ifdef CLIENT_SUBNET
else O_LST(opt, "send-client-subnet", client_subnet)
else O_LST(opt, "client-subnet-zone", client_subnet_zone)
else O_STR(opt, "client-subnet-address-override-ipv4", client_subnet_address_override_ipv4)
else O_STR(opt, "client-subnet-address-override-ipv6", client_subnet_address_override_ipv6)
else O_DEC(opt, "max-client-subnet-ipv4", max_client_subnet_ipv4)
else O_DEC(opt, "max-client-subnet-ipv6", max_client_subnet_ipv6)
else O_DEC(opt, "min-client-subnet-ipv4", min_client_subnet_ipv4)
Expand Down Expand Up @@ -1689,6 +1693,8 @@ config_delete(struct config_file* cfg)
#ifdef CLIENT_SUBNET
config_delstrlist(cfg->client_subnet);
config_delstrlist(cfg->client_subnet_zone);
free(cfg->client_subnet_address_override_ipv4);
free(cfg->client_subnet_address_override_ipv6);
#endif
free(cfg->identity);
free(cfg->version);
Expand Down
4 changes: 4 additions & 0 deletions util/config_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,10 @@ struct config_file {
struct config_strlist* client_subnet_zone;
/** opcode assigned by IANA for edns0-client-subnet option */
uint16_t client_subnet_opcode;
/** Override the outgoing client subnet source address to this value (IPv4) */
char *client_subnet_address_override_ipv4;
/** Override the outgoing client subnet source address to this value (IPv6) */
char *client_subnet_address_override_ipv6;
/** Do not check whitelist if incoming query contains an ECS record */
int client_subnet_always_forward;
/** Subnet length we are willing to give up privacy for */
Expand Down
2 changes: 2 additions & 0 deletions util/configlexer.lex
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,8 @@ send-client-subnet{COLON} { YDVAR(1, VAR_SEND_CLIENT_SUBNET) }
client-subnet-zone{COLON} { YDVAR(1, VAR_CLIENT_SUBNET_ZONE) }
client-subnet-always-forward{COLON} { YDVAR(1, VAR_CLIENT_SUBNET_ALWAYS_FORWARD) }
client-subnet-opcode{COLON} { YDVAR(1, VAR_CLIENT_SUBNET_OPCODE) }
client-subnet-address-override-ipv4{COLON} { YDVAR(1, VAR_CLIENT_SUBNET_ADDRESS_OVERRIDE_IPV4) }
client-subnet-address-override-ipv6{COLON} { YDVAR(1, VAR_CLIENT_SUBNET_ADDRESS_OVERRIDE_IPV6) }
max-client-subnet-ipv4{COLON} { YDVAR(1, VAR_MAX_CLIENT_SUBNET_IPV4) }
max-client-subnet-ipv6{COLON} { YDVAR(1, VAR_MAX_CLIENT_SUBNET_IPV6) }
min-client-subnet-ipv4{COLON} { YDVAR(1, VAR_MIN_CLIENT_SUBNET_IPV4) }
Expand Down
23 changes: 23 additions & 0 deletions util/configparser.y
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ extern struct config_parser_state* cfg_parser;
%token VAR_IP_RATELIMIT_BACKOFF VAR_RATELIMIT_BACKOFF
%token VAR_SEND_CLIENT_SUBNET VAR_CLIENT_SUBNET_ZONE
%token VAR_CLIENT_SUBNET_ALWAYS_FORWARD VAR_CLIENT_SUBNET_OPCODE
%token VAR_CLIENT_SUBNET_ADDRESS_OVERRIDE_IPV4
%token VAR_CLIENT_SUBNET_ADDRESS_OVERRIDE_IPV6
%token VAR_MAX_CLIENT_SUBNET_IPV4 VAR_MAX_CLIENT_SUBNET_IPV6
%token VAR_MIN_CLIENT_SUBNET_IPV4 VAR_MIN_CLIENT_SUBNET_IPV6
%token VAR_MAX_ECS_TREE_SIZE_IPV4 VAR_MAX_ECS_TREE_SIZE_IPV6
Expand Down Expand Up @@ -302,6 +304,7 @@ content_server: server_num_threads | server_verbosity | server_port |
server_max_sent_count | server_max_query_restarts |
server_send_client_subnet | server_client_subnet_zone |
server_client_subnet_always_forward | server_client_subnet_opcode |
server_client_subnet_address_override_ipv4 | server_client_subnet_address_override_ipv6 |
server_max_client_subnet_ipv4 | server_max_client_subnet_ipv6 |
server_min_client_subnet_ipv4 | server_min_client_subnet_ipv6 |
server_max_ecs_tree_size_ipv4 | server_max_ecs_tree_size_ipv6 |
Expand Down Expand Up @@ -693,6 +696,26 @@ server_client_subnet_opcode: VAR_CLIENT_SUBNET_OPCODE STRING_ARG
free($2);
}
;
server_client_subnet_address_override_ipv4: VAR_CLIENT_SUBNET_ADDRESS_OVERRIDE_IPV4 STRING_ARG
{
#ifdef CLIENT_SUBNET
OUTYY(("P(client_subnet_address_override_ipv4:%s)\n", $2));
cfg_parser->cfg->client_subnet_address_override_ipv4 = $2;
#else
OUTYY(("P(Compiled without edns subnet option, ignoring)\n"));
#endif
}
;
server_client_subnet_address_override_ipv6: VAR_CLIENT_SUBNET_ADDRESS_OVERRIDE_IPV6 STRING_ARG
{
#ifdef CLIENT_SUBNET
OUTYY(("P(client_subnet_address_override_ipv6:%s)\n", $2));
cfg_parser->cfg->client_subnet_address_override_ipv6 = $2;
#else
OUTYY(("P(Compiled without edns subnet option, ignoring)\n"));
#endif
}
;
server_max_client_subnet_ipv4: VAR_MAX_CLIENT_SUBNET_IPV4 STRING_ARG
{
#ifdef CLIENT_SUBNET
Expand Down