- rpz-triggers, for clientip modified answers the rpz SOA is added to the

additional section with the serial number and name of the rpz zone that
  was applied.
This commit is contained in:
W.C.A. Wijngaards 2021-05-14 15:34:48 +02:00
parent ad08971b7a
commit 50dcadd495
10 changed files with 76 additions and 17 deletions

View file

@ -402,7 +402,7 @@ prep_data(struct module_qstate* qstate, struct sldns_buffer* buf)
qstate->return_msg->rep);
if(!reply_info_answer_encode(&qstate->return_msg->qinfo,
qstate->return_msg->rep, 0, qstate->query_flags,
buf, 0, 1, qstate->env->scratch, 65535, &edns, 1, 0))
buf, 0, 1, qstate->env->scratch, 65535, &edns, 1, 0, 0))
return 0;
/* TTLs in the return_msg are relative to time(0) so we have to

View file

@ -522,7 +522,7 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
repinfo->c, worker->scratchpad) ||
!reply_info_answer_encode(&msg->qinfo, msg->rep, id, flags,
repinfo->c->buffer, 0, 1, worker->scratchpad,
udpsize, edns, (int)(edns->bits & EDNS_DO), secure)) {
udpsize, edns, (int)(edns->bits & EDNS_DO), secure, 0)) {
if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, NULL,
LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad,
worker->env.now_tv))
@ -726,7 +726,7 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
repinfo->c, worker->scratchpad) ||
!reply_info_answer_encode(qinfo, encode_rep, id, flags,
repinfo->c->buffer, timenow, 1, worker->scratchpad,
udpsize, edns, (int)(edns->bits & EDNS_DO), *is_secure_answer)) {
udpsize, edns, (int)(edns->bits & EDNS_DO), *is_secure_answer, 0)) {
if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, NULL,
LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad,
worker->env.now_tv))

View file

@ -1948,6 +1948,17 @@ static int auth_zone_zonemd_check_hash(struct auth_zone* z,
return 0;
}
/** find the apex SOA RRset, if it exists */
struct auth_rrset* auth_zone_get_soa_rrset(struct auth_zone* z)
{
struct auth_data* apex;
struct auth_rrset* soa;
apex = az_find_name(z, z->name, z->namelen);
if(!apex) return NULL;
soa = az_domain_rrset(apex, LDNS_RR_TYPE_SOA);
return soa;
}
/** find serial number of zone or false if none */
int
auth_zone_get_serial(struct auth_zone* z, uint32_t* serial)
@ -3484,7 +3495,7 @@ auth_answer_encode(struct query_info* qinfo, struct module_env* env,
*(uint16_t*)sldns_buffer_begin(buf),
sldns_buffer_read_u16_at(buf, 2),
buf, 0, 0, temp, udpsize, edns,
(int)(edns->bits&EDNS_DO), 0)) {
(int)(edns->bits&EDNS_DO), 0, 0)) {
error_encode(buf, (LDNS_RCODE_SERVFAIL|BIT_AA), qinfo,
*(uint16_t*)sldns_buffer_begin(buf),
sldns_buffer_read_u16_at(buf, 2), edns);

View file

@ -632,6 +632,9 @@ int auth_zones_startprobesequence(struct auth_zones* az,
/** read auth zone from zonefile. caller must lock zone. false on failure */
int auth_zone_read_zonefile(struct auth_zone* z, struct config_file* cfg);
/** find the apex SOA RRset, if it exists. NULL if no SOA RRset. */
struct auth_rrset* auth_zone_get_soa_rrset(struct auth_zone* z);
/** find serial number of zone or false if none (no SOA record) */
int auth_zone_get_serial(struct auth_zone* z, uint32_t* serial);

View file

@ -1261,7 +1261,7 @@ local_encode(struct query_info* qinfo, struct module_env* env,
if(!inplace_cb_reply_local_call(env, qinfo, NULL, &rep, rcode, edns,
repinfo, temp, env->now_tv) || !reply_info_answer_encode(qinfo, &rep,
*(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2),
buf, 0, 0, temp, udpsize, edns, (int)(edns->bits&EDNS_DO), 0)) {
buf, 0, 0, temp, udpsize, edns, (int)(edns->bits&EDNS_DO), 0, 0)) {
error_encode(buf, (LDNS_RCODE_SERVFAIL|BIT_AA), qinfo,
*(uint16_t*)sldns_buffer_begin(buf),
sldns_buffer_read_u16_at(buf, 2), edns);

View file

@ -1167,7 +1167,7 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep,
!reply_info_answer_encode(&m->s.qinfo, rep, r->qid,
r->qflags, r->buf, 0, 1,
m->s.env->scratch, udp_size, &r->edns,
(int)(r->edns.bits & EDNS_DO), secure))
(int)(r->edns.bits & EDNS_DO), secure, 0))
{
fptr_ok(fptr_whitelist_mesh_cb(r->cb));
(*r->cb)(r->cb_arg, LDNS_RCODE_SERVFAIL, r->buf,
@ -1313,7 +1313,7 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
!reply_info_answer_encode(&m->s.qinfo, rep, r->qid,
r->qflags, r_buffer, 0, 1, m->s.env->scratch,
udp_size, &r->edns, (int)(r->edns.bits & EDNS_DO),
secure))
secure, 0))
{
if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s,
rep, LDNS_RCODE_SERVFAIL, &r->edns, &r->query_reply, m->s.region, &r->start_time))

View file

@ -1494,20 +1494,30 @@ static int
rpz_local_encode(struct module_env* env, struct query_info* qinfo,
struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* buf,
struct regional* temp, struct ub_packed_rrset_key* rrset, int ansec,
int rcode)
int rcode, struct ub_packed_rrset_key* soa_rrset)
{
struct reply_info rep;
uint16_t udpsize;
struct ub_packed_rrset_key* rrsetlist[3];
memset(&rep, 0, sizeof(rep));
rep.flags = (uint16_t)((BIT_QR | BIT_AA | BIT_RA) | rcode);
rep.qdcount = 1;
rep.rrset_count = ansec;
rep.rrsets = rrsetlist;
if(ansec > 0) {
rep.an_numrrsets = 1;
rep.rrsets = &rrset;
rep.rrsets[0] = rrset;
rep.ttl = ((struct packed_rrset_data*)rrset->entry.data)->rr_ttl[0];
}
if(soa_rrset != NULL) {
rep.ar_numrrsets = 1;
rep.rrsets[rep.rrset_count] = soa_rrset;
rep.rrset_count ++;
if(rep.ttl < ((struct packed_rrset_data*)soa_rrset->entry.data)->rr_ttl[0]) {
rep.ttl = ((struct packed_rrset_data*)soa_rrset->entry.data)->rr_ttl[0];
}
}
udpsize = edns->udp_size;
edns->edns_version = EDNS_ADVERTISED_VERSION;
@ -1518,7 +1528,8 @@ rpz_local_encode(struct module_env* env, struct query_info* qinfo,
repinfo, temp, env->now_tv) ||
!reply_info_answer_encode(qinfo, &rep,
*(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2),
buf, 0, 0, temp, udpsize, edns, (int)(edns->bits&EDNS_DO), 0)) {
buf, 0, 0, temp, udpsize, edns, (int)(edns->bits&EDNS_DO), 0,
1 /* not minimal */ )) {
error_encode(buf, (LDNS_RCODE_SERVFAIL|BIT_AA), qinfo,
*(uint16_t*)sldns_buffer_begin(buf),
sldns_buffer_read_u16_at(buf, 2), edns);
@ -1544,11 +1555,12 @@ static void
rpz_apply_clientip_localdata_action(struct clientip_synthesized_rr* raddr,
struct module_env* env, struct query_info* qinfo,
struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* buf,
struct regional* temp)
struct regional* temp, struct auth_zone* auth_zone)
{
struct local_rrset* rrset;
enum rpz_action action = RPZ_INVALID_ACTION;
struct ub_packed_rrset_key* rp = NULL;
struct ub_packed_rrset_key* rsoa = NULL;
int rcode = LDNS_RCODE_NOERROR|BIT_AA;
int rrset_count = 1;
@ -1573,12 +1585,37 @@ rpz_apply_clientip_localdata_action(struct clientip_synthesized_rr* raddr,
return;
}
rp->rk.flags |= PACKED_RRSET_FIXEDTTL;
rp->rk.flags |= PACKED_RRSET_FIXEDTTL | PACKED_RRSET_RPZ;
rp->rk.dname = qinfo->qname;
rp->rk.dname_len = qinfo->qname_len;
rp->entry.hash = rrset_key_hash(&rp->rk);
nodata:
if(auth_zone) {
struct auth_rrset* soa = NULL;
soa = auth_zone_get_soa_rrset(auth_zone);
if(soa) {
struct ub_packed_rrset_key csoa;
memset(&csoa, 0, sizeof(csoa));
csoa.entry.key = &csoa;
csoa.rk.rrset_class = htons(LDNS_RR_CLASS_IN);
csoa.rk.type = htons(LDNS_RR_TYPE_SOA);
csoa.rk.flags |= PACKED_RRSET_FIXEDTTL
| PACKED_RRSET_RPZ;
csoa.rk.dname = auth_zone->name;
csoa.rk.dname_len = auth_zone->namelen;
csoa.entry.hash = rrset_key_hash(&csoa.rk);
csoa.entry.data = soa->data;
rsoa = respip_copy_rrset(&csoa, temp);
if(!rsoa) {
verbose(VERB_ALGO, "rpz: local data action soa: out of memory");
return;
}
}
}
rpz_local_encode(env, qinfo, edns, repinfo, buf, temp, rp,
rrset_count, rcode);
rrset_count, rcode, rsoa);
}
static inline struct dns_msg*
@ -2150,7 +2187,7 @@ rpz_apply_maybe_clientip_trigger(struct auth_zones* az, struct module_env* env,
stats->rpz_action[client_action]++;
if(client_action == RPZ_LOCAL_DATA_ACTION) {
rpz_apply_clientip_localdata_action(node, env, qinfo,
edns, repinfo, buf, temp);
edns, repinfo, buf, temp, *a_out);
} else {
if(*r_out && (*r_out)->log)
log_rpz_apply(((*z_out)?(*z_out)->name:NULL),

View file

@ -207,6 +207,8 @@ SECTION QUESTION
a.a. IN A
SECTION ANSWER
a.a. IN A 127.0.0.1
SECTION ADDITIONAL
rpz.example.com. 3600 IN SOA ns1.rpz.example.com. hostmaster.rpz.example.com. ( 1379078166 28800 7200 604800 7200 )
ENTRY_END
; should be synthesized
@ -226,6 +228,8 @@ SECTION QUESTION
a.a. IN TXT
SECTION ANSWER
a.a. IN TXT "42"
SECTION ADDITIONAL
rpz.example.com. 3600 IN SOA ns1.rpz.example.com. hostmaster.rpz.example.com. ( 1379078166 28800 7200 604800 7200 )
ENTRY_END
; should be synthesized NODATA
@ -243,6 +247,8 @@ MATCH all
REPLY QR AA RD RA NOERROR
SECTION QUESTION
a.a. IN AAAA
SECTION ADDITIONAL
rpz.example.com. 3600 IN SOA ns1.rpz.example.com. hostmaster.rpz.example.com. ( 1379078166 28800 7200 604800 7200 )
ENTRY_END
; should be DROPPED

View file

@ -878,7 +878,7 @@ int
reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep,
uint16_t id, uint16_t qflags, sldns_buffer* pkt, time_t timenow,
int cached, struct regional* region, uint16_t udpsize,
struct edns_data* edns, int dnssec, int secure)
struct edns_data* edns, int dnssec, int secure, int notminimal)
{
uint16_t flags;
unsigned int attach_edns = 0;
@ -916,7 +916,7 @@ reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep,
}
if(!reply_info_encode(qinf, rep, id, flags, pkt, timenow, region,
udpsize, dnssec, MINIMAL_RESPONSES)) {
udpsize, dnssec, (notminimal?0:MINIMAL_RESPONSES))) {
log_err("reply encode: out of memory");
return 0;
}

View file

@ -64,12 +64,14 @@ struct edns_data;
* or if edns_present = 0, it is not included.
* @param dnssec: if 0 DNSSEC records are omitted from the answer.
* @param secure: if 1, the AD bit is set in the reply.
* @param notminimal: if 1, ignore minimalresponses and include additional
* section anyway.
* @return: 0 on error (server failure).
*/
int reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep,
uint16_t id, uint16_t qflags, struct sldns_buffer* dest, time_t timenow,
int cached, struct regional* region, uint16_t udpsize,
struct edns_data* edns, int dnssec, int secure);
struct edns_data* edns, int dnssec, int secure, int notminimal);
/**
* Regenerate the wireformat from the stored msg reply.