]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- rpz-triggers, for clientip modified answers the rpz SOA is added to the
authorW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Fri, 14 May 2021 13:34:48 +0000 (15:34 +0200)
committerW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Fri, 14 May 2021 13:34:48 +0000 (15:34 +0200)
  additional section with the serial number and name of the rpz zone that
  was applied.

cachedb/cachedb.c
daemon/worker.c
services/authzone.c
services/authzone.h
services/localzone.c
services/mesh.c
services/rpz.c
testdata/rpz_clientip.rpl
util/data/msgencode.c
util/data/msgencode.h

index af4ffe5f28b5d05dd1437bad71212d1bdbd18c69..707319e85767a38d53300914c55720756c326e94 100644 (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
index 2ee8b8d9b5d248343e147aee6db259a92744600b..421cd82c4f1bc1f154bd2e2da2ff06fde558b407 100644 (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))
index 196fe6693d958277d6e6ffb3a447769544d3eeb2..19f4625861d1ca1475cebf8e0fd0393b5bf4f27e 100644 (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);
index 4810017a31e4d07f1725d1da65a209311b298533..7b9fc60fc4d74e2397e663b6a78e161205c6a540 100644 (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);
 
index a24137eacd8d6336638171fcc65582582a7acea1..6eecab62aaad78032b4f137379d855ddf3c91d7c 100644 (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);
index f00ad3e86c542989ef69a294934485f76d424fa8..3ff14a0ddbf23e6ba71d7ae6193e051dc575dfb2 100644 (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))
index e53c5cf8115f05c5f5667cd6ea2c286a777b3ed7..9e3510b7d7736cc1734239a7a79a134fddc53532 100644 (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),
index 64082210cd3a2d2a77fbec04b23b5c7c384f386e..7d5b5330d33fff87d24c97ec569cd4b22a3b41ac 100644 (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
index 5f297b551bfb179b9dd61a4113b3fa93cfec0d09..1cf30dd5d47158bcd3f068288199d0c723cc1708 100644 (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;
        }
index 30dc515cbe595eadcb0bf58b5ded21b32e55296c..3baa0eaf983f3779c88c0d0fd6c01d35e8e34b07 100644 (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.