- Add harden-unknown-additional option. Default on and it removes

unknown records from the authority section and additional section.
  Thanks to Xiang Li, from NISL Lab, Tsinghua University.
This commit is contained in:
W.C.A. Wijngaards 2023-01-19 14:59:18 +01:00
parent d69f875261
commit 8df1e58209
14 changed files with 4477 additions and 4328 deletions

View file

@ -5,6 +5,9 @@
resolvers. The new choice, down from 4096 means it is harder to get resolvers. The new choice, down from 4096 means it is harder to get
large responses from Unbound. Thanks to Xiang Li, from NISL Lab, large responses from Unbound. Thanks to Xiang Li, from NISL Lab,
Tsinghua University. Tsinghua University.
- Add harden-unknown-additional option. Default on and it removes
unknown records from the authority section and additional section.
Thanks to Xiang Li, from NISL Lab, Tsinghua University.
18 January 2023: Wouter 18 January 2023: Wouter
- Fix not following cleared RD flags potentially enables amplification - Fix not following cleared RD flags potentially enables amplification

View file

@ -503,6 +503,10 @@ server:
# to validate the zone. # to validate the zone.
# harden-algo-downgrade: no # harden-algo-downgrade: no
# Harden against unknown records in the authority section and the
# additional section.
# harden-unknown-additional: yes
# Sent minimum amount of information to upstream servers to enhance # Sent minimum amount of information to upstream servers to enhance
# privacy. Only sent minimum required labels of the QNAME and set QTYPE # privacy. Only sent minimum required labels of the QNAME and set QTYPE
# to A when possible. # to A when possible.

View file

@ -1020,6 +1020,11 @@ validate the zone. Default is no. Zone signers must produce zones
that allow this feature to work, but sometimes they do not, and turning that allow this feature to work, but sometimes they do not, and turning
this option off avoids that validation failure. this option off avoids that validation failure.
.TP .TP
.B harden\-unknown\-additional: \fI<yes or no>
Harden against unknown records in the authority section and additional
section. Default is yes. If no, such records are copied from the upstream
and presented to the client together with the answer.
.TP
.B use\-caps\-for\-id: \fI<yes or no> .B use\-caps\-for\-id: \fI<yes or no>
Use 0x20\-encoded random bits in the query to foil spoof attempts. Use 0x20\-encoded random bits in the query to foil spoof attempts.
This perturbs the lowercase and uppercase of query names sent to This perturbs the lowercase and uppercase of query names sent to

View file

@ -346,6 +346,26 @@ soa_in_auth(struct msg_parse* msg)
return 0; return 0;
} }
/** Check if type is allowed in the authority section */
static int
type_allowed_in_authority_section(uint16_t tp)
{
if(tp == LDNS_RR_TYPE_SOA || tp == LDNS_RR_TYPE_NS ||
tp == LDNS_RR_TYPE_DS || tp == LDNS_RR_TYPE_NSEC ||
tp == LDNS_RR_TYPE_NSEC3)
return 1;
return 0;
}
/** Check if type is allowed in the additional section */
static int
type_allowed_in_additional_section(uint16_t tp)
{
if(tp == LDNS_RR_TYPE_A || tp == LDNS_RR_TYPE_AAAA)
return 1;
return 0;
}
/** /**
* This routine normalizes a response. This includes removing "irrelevant" * This routine normalizes a response. This includes removing "irrelevant"
* records from the answer and additional sections and (re)synthesizing * records from the answer and additional sections and (re)synthesizing
@ -355,11 +375,13 @@ soa_in_auth(struct msg_parse* msg)
* @param msg: msg to normalize. * @param msg: msg to normalize.
* @param qinfo: original query. * @param qinfo: original query.
* @param region: where to allocate synthesized CNAMEs. * @param region: where to allocate synthesized CNAMEs.
* @param env: module env with config options.
* @return 0 on error. * @return 0 on error.
*/ */
static int static int
scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg, scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
struct query_info* qinfo, struct regional* region) struct query_info* qinfo, struct regional* region,
struct module_env* env)
{ {
uint8_t* sname = qinfo->qname; uint8_t* sname = qinfo->qname;
size_t snamelen = qinfo->qname_len; size_t snamelen = qinfo->qname_len;
@ -511,6 +533,7 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
/* Mark additional names from AUTHORITY */ /* Mark additional names from AUTHORITY */
while(rrset && rrset->section == LDNS_SECTION_AUTHORITY) { while(rrset && rrset->section == LDNS_SECTION_AUTHORITY) {
/* protect internals of recursor by making sure to del these */
if(rrset->type==LDNS_RR_TYPE_DNAME || if(rrset->type==LDNS_RR_TYPE_DNAME ||
rrset->type==LDNS_RR_TYPE_CNAME || rrset->type==LDNS_RR_TYPE_CNAME ||
rrset->type==LDNS_RR_TYPE_A || rrset->type==LDNS_RR_TYPE_A ||
@ -519,6 +542,13 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
"RRset:", pkt, msg, prev, &rrset); "RRset:", pkt, msg, prev, &rrset);
continue; continue;
} }
/* Allowed list of types in the authority section */
if(env->cfg->harden_unknown_additional &&
!type_allowed_in_authority_section(rrset->type)) {
remove_rrset("normalize: removing irrelevant "
"RRset:", pkt, msg, prev, &rrset);
continue;
}
/* only one NS set allowed in authority section */ /* only one NS set allowed in authority section */
if(rrset->type==LDNS_RR_TYPE_NS) { if(rrset->type==LDNS_RR_TYPE_NS) {
/* NS set must be pertinent to the query */ /* NS set must be pertinent to the query */
@ -576,7 +606,6 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
* found in ANSWER and AUTHORITY. */ * found in ANSWER and AUTHORITY. */
/* These records have not been marked OK previously */ /* These records have not been marked OK previously */
while(rrset && rrset->section == LDNS_SECTION_ADDITIONAL) { while(rrset && rrset->section == LDNS_SECTION_ADDITIONAL) {
/* FIXME: what about other types? */
if(rrset->type==LDNS_RR_TYPE_A || if(rrset->type==LDNS_RR_TYPE_A ||
rrset->type==LDNS_RR_TYPE_AAAA) rrset->type==LDNS_RR_TYPE_AAAA)
{ {
@ -589,6 +618,7 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
continue; continue;
} }
} }
/* protect internals of recursor by making sure to del these */
if(rrset->type==LDNS_RR_TYPE_DNAME || if(rrset->type==LDNS_RR_TYPE_DNAME ||
rrset->type==LDNS_RR_TYPE_CNAME || rrset->type==LDNS_RR_TYPE_CNAME ||
rrset->type==LDNS_RR_TYPE_NS) { rrset->type==LDNS_RR_TYPE_NS) {
@ -596,6 +626,13 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
"RRset:", pkt, msg, prev, &rrset); "RRset:", pkt, msg, prev, &rrset);
continue; continue;
} }
/* Allowed list of types in the additional section */
if(env->cfg->harden_unknown_additional &&
!type_allowed_in_additional_section(rrset->type)) {
remove_rrset("normalize: removing irrelevant "
"RRset:", pkt, msg, prev, &rrset);
continue;
}
prev = rrset; prev = rrset;
rrset = rrset->rrset_all_next; rrset = rrset->rrset_all_next;
} }
@ -846,7 +883,7 @@ scrub_message(sldns_buffer* pkt, struct msg_parse* msg,
} }
/* normalize the response, this cleans up the additional. */ /* normalize the response, this cleans up the additional. */
if(!scrub_normalize(pkt, msg, qinfo, region)) if(!scrub_normalize(pkt, msg, qinfo, region, env))
return 0; return 0;
/* delete all out-of-zone information */ /* delete all out-of-zone information */
if(!scrub_sanitize(pkt, msg, qinfo, zonename, env, ie)) if(!scrub_sanitize(pkt, msg, qinfo, zonename, env, ie))

View file

@ -195,10 +195,8 @@ SECTION ADDITIONAL
open.example.com. 600 IN A 213.154.224.1 open.example.com. 600 IN A 213.154.224.1
open.example.com. 600 IN AAAA 2001:7b8:206:1::53 open.example.com. 600 IN AAAA 2001:7b8:206:1::53
open.example.com. 600 IN AAAA 2001:7b8:206:1::1 open.example.com. 600 IN AAAA 2001:7b8:206:1::1
_sip._udp.example.com. 600 IN SRV 0 0 5060 johnny.example.com.
open.example.com. 600 IN RRSIG A 3 3 600 20070926134150 20070829134150 2854 example.com. MC0CFQCh8bja923UJmg1+sYXMK8WIE4dpgIUQe9sZa0GOcUYSgb2rXoogF8af+Y= ;{id = 2854} open.example.com. 600 IN RRSIG A 3 3 600 20070926134150 20070829134150 2854 example.com. MC0CFQCh8bja923UJmg1+sYXMK8WIE4dpgIUQe9sZa0GOcUYSgb2rXoogF8af+Y= ;{id = 2854}
open.example.com. 600 IN RRSIG AAAA 3 3 600 20070926134150 20070829134150 2854 example.com. MC0CFQCRGJgIS6kEVG7aJfovuG/q3cgOWwIUYEIFCnfRQlMIYWF7BKMQoMbdkE0= ;{id = 2854} open.example.com. 600 IN RRSIG AAAA 3 3 600 20070926134150 20070829134150 2854 example.com. MC0CFQCRGJgIS6kEVG7aJfovuG/q3cgOWwIUYEIFCnfRQlMIYWF7BKMQoMbdkE0= ;{id = 2854}
_sip._udp.example.com. 600 IN RRSIG SRV 3 4 600 20070926134150 20070829134150 2854 example.com. MCwCFFSRVgOcq1ihVuO6MhCuzWs6SxpVAhRPHHCKy0JxymVkYeFOxTkbVSWMMw== ;{id = 2854}
ENTRY_END ENTRY_END
SCENARIO_END SCENARIO_END

View file

@ -8,6 +8,8 @@ server:
fake-sha1: yes fake-sha1: yes
trust-anchor-signaling: no trust-anchor-signaling: no
rrset-roundrobin: no rrset-roundrobin: no
; this allows the SRV entry in the answer packet additional section.
harden-unknown-additional: no
stub-zone: stub-zone:
name: "." name: "."

View file

@ -232,10 +232,8 @@ SECTION ADDITIONAL
open.example.com. 600 IN A 213.154.224.1 open.example.com. 600 IN A 213.154.224.1
open.example.com. 600 IN AAAA 2001:7b8:206:1::53 open.example.com. 600 IN AAAA 2001:7b8:206:1::53
open.example.com. 600 IN AAAA 2001:7b8:206:1::1 open.example.com. 600 IN AAAA 2001:7b8:206:1::1
_sip._udp.example.com. 600 IN SRV 0 0 5060 johnny.example.com.
open.example.com. 600 IN RRSIG A 3 3 600 20070926134150 20070829134150 2854 example.com. MC0CFQCh8bja923UJmg1+sYXMK8WIE4dpgIUQe9sZa0GOcUYSgb2rXoogF8af+Y= ;{id = 2854} open.example.com. 600 IN RRSIG A 3 3 600 20070926134150 20070829134150 2854 example.com. MC0CFQCh8bja923UJmg1+sYXMK8WIE4dpgIUQe9sZa0GOcUYSgb2rXoogF8af+Y= ;{id = 2854}
open.example.com. 600 IN RRSIG AAAA 3 3 600 20070926134150 20070829134150 2854 example.com. MC0CFQCRGJgIS6kEVG7aJfovuG/q3cgOWwIUYEIFCnfRQlMIYWF7BKMQoMbdkE0= ;{id = 2854} open.example.com. 600 IN RRSIG AAAA 3 3 600 20070926134150 20070829134150 2854 example.com. MC0CFQCRGJgIS6kEVG7aJfovuG/q3cgOWwIUYEIFCnfRQlMIYWF7BKMQoMbdkE0= ;{id = 2854}
_sip._udp.example.com. 600 IN RRSIG SRV 3 4 600 20070926134150 20070829134150 2854 example.com. MCwCFFSRVgOcq1ihVuO6MhCuzWs6SxpVAhRPHHCKy0JxymVkYeFOxTkbVSWMMw== ;{id = 2854}
ENTRY_END ENTRY_END
SCENARIO_END SCENARIO_END

View file

@ -233,6 +233,7 @@ config_create(void)
cfg->harden_below_nxdomain = 1; cfg->harden_below_nxdomain = 1;
cfg->harden_referral_path = 0; cfg->harden_referral_path = 0;
cfg->harden_algo_downgrade = 0; cfg->harden_algo_downgrade = 0;
cfg->harden_unknown_additional = 1;
cfg->use_caps_bits_for_id = 0; cfg->use_caps_bits_for_id = 0;
cfg->caps_whitelist = NULL; cfg->caps_whitelist = NULL;
cfg->private_address = NULL; cfg->private_address = NULL;
@ -649,6 +650,7 @@ int config_set_option(struct config_file* cfg, const char* opt,
else S_YNO("harden-below-nxdomain:", harden_below_nxdomain) else S_YNO("harden-below-nxdomain:", harden_below_nxdomain)
else S_YNO("harden-referral-path:", harden_referral_path) else S_YNO("harden-referral-path:", harden_referral_path)
else S_YNO("harden-algo-downgrade:", harden_algo_downgrade) else S_YNO("harden-algo-downgrade:", harden_algo_downgrade)
else S_YNO("harden-unknown-additional:", harden_unknown_additional)
else S_YNO("use-caps-for-id:", use_caps_bits_for_id) else S_YNO("use-caps-for-id:", use_caps_bits_for_id)
else S_STRLIST("caps-whitelist:", caps_whitelist) else S_STRLIST("caps-whitelist:", caps_whitelist)
else S_SIZET_OR_ZERO("unwanted-reply-threshold:", unwanted_threshold) else S_SIZET_OR_ZERO("unwanted-reply-threshold:", unwanted_threshold)
@ -1117,6 +1119,7 @@ config_get_option(struct config_file* cfg, const char* opt,
else O_YNO(opt, "harden-below-nxdomain", harden_below_nxdomain) else O_YNO(opt, "harden-below-nxdomain", harden_below_nxdomain)
else O_YNO(opt, "harden-referral-path", harden_referral_path) else O_YNO(opt, "harden-referral-path", harden_referral_path)
else O_YNO(opt, "harden-algo-downgrade", harden_algo_downgrade) else O_YNO(opt, "harden-algo-downgrade", harden_algo_downgrade)
else O_YNO(opt, "harden-unknown-additional", harden_unknown_additional)
else O_YNO(opt, "use-caps-for-id", use_caps_bits_for_id) else O_YNO(opt, "use-caps-for-id", use_caps_bits_for_id)
else O_LST(opt, "caps-whitelist", caps_whitelist) else O_LST(opt, "caps-whitelist", caps_whitelist)
else O_DEC(opt, "unwanted-reply-threshold", unwanted_threshold) else O_DEC(opt, "unwanted-reply-threshold", unwanted_threshold)

View file

@ -292,6 +292,9 @@ struct config_file {
int harden_referral_path; int harden_referral_path;
/** harden against algorithm downgrade */ /** harden against algorithm downgrade */
int harden_algo_downgrade; int harden_algo_downgrade;
/** harden against unknown records in the authority section and in
* the additional section */
int harden_unknown_additional;
/** use 0x20 bits in query as random ID bits */ /** use 0x20 bits in query as random ID bits */
int use_caps_bits_for_id; int use_caps_bits_for_id;
/** 0x20 whitelist, domains that do not use capsforid */ /** 0x20 whitelist, domains that do not use capsforid */

File diff suppressed because it is too large Load diff

View file

@ -316,6 +316,7 @@ harden-dnssec-stripped{COLON} { YDVAR(1, VAR_HARDEN_DNSSEC_STRIPPED) }
harden-below-nxdomain{COLON} { YDVAR(1, VAR_HARDEN_BELOW_NXDOMAIN) } harden-below-nxdomain{COLON} { YDVAR(1, VAR_HARDEN_BELOW_NXDOMAIN) }
harden-referral-path{COLON} { YDVAR(1, VAR_HARDEN_REFERRAL_PATH) } harden-referral-path{COLON} { YDVAR(1, VAR_HARDEN_REFERRAL_PATH) }
harden-algo-downgrade{COLON} { YDVAR(1, VAR_HARDEN_ALGO_DOWNGRADE) } harden-algo-downgrade{COLON} { YDVAR(1, VAR_HARDEN_ALGO_DOWNGRADE) }
harden-unknown-additional{COLON} { YDVAR(1, VAR_HARDEN_UNKNOWN_ADDITIONAL) }
use-caps-for-id{COLON} { YDVAR(1, VAR_USE_CAPS_FOR_ID) } use-caps-for-id{COLON} { YDVAR(1, VAR_USE_CAPS_FOR_ID) }
caps-whitelist{COLON} { YDVAR(1, VAR_CAPS_WHITELIST) } caps-whitelist{COLON} { YDVAR(1, VAR_CAPS_WHITELIST) }
caps-exempt{COLON} { YDVAR(1, VAR_CAPS_WHITELIST) } caps-exempt{COLON} { YDVAR(1, VAR_CAPS_WHITELIST) }

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
/* A Bison parser, made by GNU Bison 3.8.2. */ /* A Bison parser, made by GNU Bison 3.7.6. */
/* Bison interface for Yacc-like parsers in C /* Bison interface for Yacc-like parsers in C
@ -387,7 +387,8 @@ extern int yydebug;
VAR_INTERFACE_TAG_ACTION = 588, /* VAR_INTERFACE_TAG_ACTION */ VAR_INTERFACE_TAG_ACTION = 588, /* VAR_INTERFACE_TAG_ACTION */
VAR_INTERFACE_TAG_DATA = 589, /* VAR_INTERFACE_TAG_DATA */ VAR_INTERFACE_TAG_DATA = 589, /* VAR_INTERFACE_TAG_DATA */
VAR_PROXY_PROTOCOL_PORT = 590, /* VAR_PROXY_PROTOCOL_PORT */ VAR_PROXY_PROTOCOL_PORT = 590, /* VAR_PROXY_PROTOCOL_PORT */
VAR_STATISTICS_INHIBIT_ZERO = 591 /* VAR_STATISTICS_INHIBIT_ZERO */ VAR_STATISTICS_INHIBIT_ZERO = 591, /* VAR_STATISTICS_INHIBIT_ZERO */
VAR_HARDEN_UNKNOWN_ADDITIONAL = 592 /* VAR_HARDEN_UNKNOWN_ADDITIONAL */
}; };
typedef enum yytokentype yytoken_kind_t; typedef enum yytokentype yytoken_kind_t;
#endif #endif
@ -730,6 +731,7 @@ extern int yydebug;
#define VAR_INTERFACE_TAG_DATA 589 #define VAR_INTERFACE_TAG_DATA 589
#define VAR_PROXY_PROTOCOL_PORT 590 #define VAR_PROXY_PROTOCOL_PORT 590
#define VAR_STATISTICS_INHIBIT_ZERO 591 #define VAR_STATISTICS_INHIBIT_ZERO 591
#define VAR_HARDEN_UNKNOWN_ADDITIONAL 592
/* Value type. */ /* Value type. */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
@ -739,7 +741,7 @@ union YYSTYPE
char* str; char* str;
#line 743 "util/configparser.h" #line 745 "util/configparser.h"
}; };
typedef union YYSTYPE YYSTYPE; typedef union YYSTYPE YYSTYPE;
@ -750,8 +752,6 @@ typedef union YYSTYPE YYSTYPE;
extern YYSTYPE yylval; extern YYSTYPE yylval;
int yyparse (void); int yyparse (void);
#endif /* !YY_YY_UTIL_CONFIGPARSER_H_INCLUDED */ #endif /* !YY_YY_UTIL_CONFIGPARSER_H_INCLUDED */

View file

@ -194,6 +194,7 @@ extern struct config_parser_state* cfg_parser;
%token VAR_INTERFACE_ACTION VAR_INTERFACE_VIEW VAR_INTERFACE_TAG %token VAR_INTERFACE_ACTION VAR_INTERFACE_VIEW VAR_INTERFACE_TAG
%token VAR_INTERFACE_TAG_ACTION VAR_INTERFACE_TAG_DATA %token VAR_INTERFACE_TAG_ACTION VAR_INTERFACE_TAG_DATA
%token VAR_PROXY_PROTOCOL_PORT VAR_STATISTICS_INHIBIT_ZERO %token VAR_PROXY_PROTOCOL_PORT VAR_STATISTICS_INHIBIT_ZERO
%token VAR_HARDEN_UNKNOWN_ADDITIONAL
%% %%
toplevelvars: /* empty */ | toplevelvars toplevelvar ; toplevelvars: /* empty */ | toplevelvars toplevelvar ;
@ -323,7 +324,8 @@ content_server: server_num_threads | server_verbosity | server_port |
server_zonemd_permissive_mode | server_max_reuse_tcp_queries | server_zonemd_permissive_mode | server_max_reuse_tcp_queries |
server_tcp_reuse_timeout | server_tcp_auth_query_timeout | server_tcp_reuse_timeout | server_tcp_auth_query_timeout |
server_interface_automatic_ports | server_ede | server_interface_automatic_ports | server_ede |
server_proxy_protocol_port | server_statistics_inhibit_zero server_proxy_protocol_port | server_statistics_inhibit_zero |
server_harden_unknown_additional
; ;
stubstart: VAR_STUB_ZONE stubstart: VAR_STUB_ZONE
{ {
@ -1778,6 +1780,16 @@ server_harden_algo_downgrade: VAR_HARDEN_ALGO_DOWNGRADE STRING_ARG
free($2); free($2);
} }
; ;
server_harden_unknown_additional: VAR_HARDEN_UNKNOWN_ADDITIONAL STRING_ARG
{
OUTYY(("P(server_harden_unknown_additional:%s)\n", $2));
if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
yyerror("expected yes or no.");
else cfg_parser->cfg->harden_unknown_additional =
(strcmp($2, "yes")==0);
free($2);
}
;
server_use_caps_for_id: VAR_USE_CAPS_FOR_ID STRING_ARG server_use_caps_for_id: VAR_USE_CAPS_FOR_ID STRING_ARG
{ {
OUTYY(("P(server_use_caps_for_id:%s)\n", $2)); OUTYY(("P(server_use_caps_for_id:%s)\n", $2));