mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-02-16 17:18:51 -05:00
- 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:
parent
ad08971b7a
commit
50dcadd495
10 changed files with 76 additions and 17 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
6
testdata/rpz_clientip.rpl
vendored
6
testdata/rpz_clientip.rpl
vendored
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Reference in a new issue