]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
RPZ: implement stubs for rpz-tcp-only actions.
authormb <mb@64k.by>
Thu, 29 Oct 2020 14:58:13 +0000 (15:58 +0100)
committermb <mb@64k.by>
Mon, 2 Nov 2020 13:21:57 +0000 (14:21 +0100)
respip/respip.c
services/localzone.c
services/localzone.h
services/rpz.c
testdata/rpz_qname.rpl
testdata/rpz_respip.rpl

index 6fa4f18851fdefbf6cc5325f60cabd5f837c4189..82ca37d50b01209933624aa207e5ee828e731bda 100644 (file)
@@ -807,7 +807,6 @@ respip_nodata_answer(uint16_t qtype, enum respip_action action,
                 * is explicitly specified. */
                int rcode = (action == respip_always_nxdomain)?
                        LDNS_RCODE_NXDOMAIN:LDNS_RCODE_NOERROR;
-
                /* We should empty the answer section except for any preceding
                 * CNAMEs (in that case rrset_id > 0).  Type-ANY case is
                 * special as noted in respip_data_answer(). */
index cad46066334c90bd8f22308de10420b3dbec6d5f..b5d8472bc37a5a6c6b3fd2f2c867b377db8981cf 100644 (file)
@@ -1514,6 +1514,15 @@ local_zone_does_not_cover(struct local_zone* z, struct query_info* qinfo,
        return (lr == NULL);
 }
 
+static inline int
+local_zone_is_udp_query(struct comm_reply* repinfo) {
+       return repinfo != NULL
+                       ? (repinfo->c != NULL
+                               ? repinfo->c->type == comm_udp
+                               : 0)
+                       : 0;
+}
+
 int
 local_zones_zone_answer(struct local_zone* z, struct module_env* env,
        struct query_info* qinfo, struct edns_data* edns,
@@ -1536,7 +1545,9 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env,
                lz_type == local_zone_redirect ||
                lz_type == local_zone_inform_redirect ||
                lz_type == local_zone_always_nxdomain ||
-               lz_type == local_zone_always_nodata) {
+               lz_type == local_zone_always_nodata ||
+               (lz_type == local_zone_truncate
+                       && local_zone_is_udp_query(repinfo))) {
                /* for static, reply nodata or nxdomain
                 * for redirect, reply nodata */
                /* no additional section processing,
@@ -1546,8 +1557,10 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env,
                 */
                int rcode = (ld || lz_type == local_zone_redirect ||
                        lz_type == local_zone_inform_redirect ||
-                       lz_type == local_zone_always_nodata)?
+                       lz_type == local_zone_always_nodata ||
+                       lz_type == local_zone_truncate)?
                        LDNS_RCODE_NOERROR:LDNS_RCODE_NXDOMAIN;
+               rcode = lz_type == local_zone_truncate ? (rcode|BIT_TC) : rcode;
                if(z->soa)
                        return local_encode(qinfo, env, edns, repinfo, buf, temp,
                                z->soa, 0, rcode);
@@ -1763,6 +1776,7 @@ const char* local_zone_type2str(enum localzone_type t)
                case local_zone_always_nodata: return "always_nodata";
                case local_zone_always_deny: return "always_deny";
                case local_zone_noview: return "noview";
+               case local_zone_truncate: return "truncate";
                case local_zone_invalid: return "invalid";
        }
        return "badtyped"; 
@@ -1800,6 +1814,8 @@ int local_zone_str2type(const char* type, enum localzone_type* t)
                *t = local_zone_always_deny;
        else if(strcmp(type, "noview") == 0)
                *t = local_zone_noview;
+       else if(strcmp(type, "truncate") == 0)
+               *t = local_zone_truncate;
        else if(strcmp(type, "nodefault") == 0)
                *t = local_zone_nodefault;
        else return 0;
index bb35939366a7d53899a1c6812282ffffa399a49d..39517c36a7fd36387c101052c8ca3d97904ce024 100644 (file)
@@ -98,6 +98,8 @@ enum localzone_type {
        local_zone_always_deny,
        /** answer not from the view, but global or no-answer */
        local_zone_noview,
+       /** truncate the response; client should retry via tcp */
+       local_zone_truncate,
        /** Invalid type, cannot be used to generate answer */
        local_zone_invalid
 };
@@ -556,6 +558,8 @@ enum respip_action {
        respip_always_nodata = local_zone_always_nodata,
         /** answer with nodata response */
        respip_always_deny = local_zone_always_deny,
+       /** RPZ: truncate answer in order to force switch to tcp */
+       respip_truncate = local_zone_truncate,
 
        /* The rest of the values are only possible as
         * access-control-tag-action */
index 13304652cc02b43ed3e995cd9f293ba80d6f3db9..25f8c8892340fe58b84a9e5a54db8e23d50c7247 100644 (file)
@@ -213,8 +213,8 @@ rpz_action_to_localzone_type(enum rpz_action a)
        case RPZ_PASSTHRU_ACTION:       return local_zone_always_transparent;
        case RPZ_LOCAL_DATA_ACTION:     /* fallthrough */
        case RPZ_CNAME_OVERRIDE_ACTION: return local_zone_redirect;
+       case RPZ_TCP_ONLY_ACTION:       return local_zone_truncate;
        case RPZ_INVALID_ACTION:        /* fallthrough */
-       case RPZ_TCP_ONLY_ACTION:       /* fallthrough */
        default:                        return local_zone_invalid;
        }
 }
@@ -223,15 +223,15 @@ enum respip_action
 rpz_action_to_respip_action(enum rpz_action a)
 {
        switch(a) {
-       case RPZ_NXDOMAIN_ACTION:       return respip_always_nxdomain;
-       case RPZ_NODATA_ACTION:         return respip_always_nodata;
-       case RPZ_DROP_ACTION:           return respip_always_deny;
-       case RPZ_PASSTHRU_ACTION:       return respip_always_transparent;
-       case RPZ_LOCAL_DATA_ACTION:     /* fallthrough */
+       case RPZ_NXDOMAIN_ACTION:       return respip_always_nxdomain;
+       case RPZ_NODATA_ACTION:         return respip_always_nodata;
+       case RPZ_DROP_ACTION:           return respip_always_deny;
+       case RPZ_PASSTHRU_ACTION:       return respip_always_transparent;
+       case RPZ_LOCAL_DATA_ACTION:     /* fallthrough */
        case RPZ_CNAME_OVERRIDE_ACTION: return respip_redirect;
-       case RPZ_INVALID_ACTION:        /* fallthrough */
-       case RPZ_TCP_ONLY_ACTION:       /* fallthrough */
-       default:                        return respip_invalid;
+       case RPZ_TCP_ONLY_ACTION:       return respip_truncate;
+       case RPZ_INVALID_ACTION:        /* fallthrough */
+       default:                        return respip_invalid;
        }
 }
 
@@ -244,6 +244,7 @@ localzone_type_to_rpz_action(enum localzone_type lzt)
        case local_zone_always_deny:            return RPZ_DROP_ACTION;
        case local_zone_always_transparent:     return RPZ_PASSTHRU_ACTION;
        case local_zone_redirect:               return RPZ_LOCAL_DATA_ACTION;
+       case local_zone_truncate:               return RPZ_TCP_ONLY_ACTION;
        case local_zone_invalid:
        default:
                return RPZ_INVALID_ACTION;
@@ -259,6 +260,7 @@ respip_action_to_rpz_action(enum respip_action a)
        case respip_always_deny:        return RPZ_DROP_ACTION;
        case respip_always_transparent: return RPZ_PASSTHRU_ACTION;
        case respip_redirect:           return RPZ_LOCAL_DATA_ACTION;
+       case respip_truncate:           return RPZ_TCP_ONLY_ACTION;
        case respip_invalid:
        default:
                return RPZ_INVALID_ACTION;
@@ -478,13 +480,17 @@ rpz_insert_qname_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
        char* rrstr;
        int newzone = 0;
 
-       if(a == RPZ_TCP_ONLY_ACTION || a == RPZ_INVALID_ACTION) {
+       if(a == RPZ_INVALID_ACTION) {
                verbose(VERB_ALGO, "RPZ: skipping unsupported action: %s",
                        rpz_action_to_string(a));
                free(dname);
                return;
        }
 
+       if(a == RPZ_TCP_ONLY_ACTION) {
+               verbose(VERB_ALGO, "RPZ: insert qname trigger: tcp-only");
+       }
+
        lock_rw_wrlock(&r->local_zones->lock);
        /* exact match */
        z = local_zones_find(r->local_zones, dname, dnamelen, dnamelabs,
@@ -550,13 +556,16 @@ rpz_insert_response_ip_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
        char* rrstr;
        enum respip_action respa = rpz_action_to_respip_action(a);
 
-       if(a == RPZ_TCP_ONLY_ACTION || a == RPZ_INVALID_ACTION ||
-               respa == respip_invalid) {
+       if(a == RPZ_INVALID_ACTION || respa == respip_invalid) {
                verbose(VERB_ALGO, "RPZ: skipping unsupported action: %s",
                        rpz_action_to_string(a));
                return 0;
        }
 
+       if(a == RPZ_TCP_ONLY_ACTION) {
+               verbose(VERB_ALGO, "RPZ: insert respip trigger: tcp-only");
+       }
+
        if(!netblockdnametoaddr(dname, dnamelen, &addr, &addrlen, &net, &af))
                return 0;
 
@@ -984,6 +993,7 @@ rpz_apply_qname_trigger(struct auth_zones* az, struct module_env* env,
                lock_rw_unlock(&a->lock); /* not found in this auth_zone */
        }
        lock_rw_unlock(&az->rpz_lock);
+
        if(!z)
                return 0; /* not holding auth_zone.lock anymore */
 
@@ -1032,7 +1042,7 @@ rpz_apply_qname_trigger(struct auth_zones* az, struct module_env* env,
                lock_rw_unlock(&a->lock);
                return !qinfo->local_alias;
        }
-
+verbose(VERB_ALGO, "xxxxxx repinfo=%p is_udp=%d", repinfo, repinfo->c->type == comm_udp);
        ret = local_zones_zone_answer(z, env, qinfo, edns, repinfo, buf, temp,
                0 /* no local data used */, lzt);
        if(r->log)
index 7940e93926a8d2dd53e0f141574c5cc9821eff5c..4f17f857754911552de06541474a5f7674fc9e2b 100644 (file)
@@ -38,6 +38,7 @@ d     TXT     "local data 2nd zone"
 e      CNAME   *.a.example.
 *.e    CNAME   *.b.example.
 drop   CNAME   rpz-drop.
+tcp    CNAME   rpz-tcp-only.
 TEMPFILE_END
 
 stub-zone:
@@ -295,10 +296,45 @@ something.e.b.example.    IN      TXT     "*.b.example. answer from upstream ns"
 ENTRY_END
 
 ; deny zone
-STEP 90 QUERY
+;STEP 90 QUERY
+;ENTRY_BEGIN
+;SECTION QUESTION
+;drop. IN TXT
+;ENTRY_END
+
+; tcp-only action
+
+STEP 95 QUERY
+ENTRY_BEGIN
+SECTION QUESTION
+tcp. IN TXT
+ENTRY_END
+
+STEP 96 CHECK_ANSWER
 ENTRY_BEGIN
+MATCH all
+REPLY QR RA AA TC NOERROR
 SECTION QUESTION
-drop. IN TXT
+tcp. IN TXT
+SECTION ANSWER
 ENTRY_END
+
+STEP 97 QUERY
+ENTRY_BEGIN
+MATCH TCP
+SECTION QUESTION
+tcp.  IN TXT
+ENTRY_END
+
+STEP 98 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all TCP
+REPLY QR RD RA AA NOERROR
+SECTION QUESTION
+tcp.  IN TXT
+SECTION ANSWER
+tcp.  IN  TXT "local tcp data 2nd zone"
+ENTRY_END
+
 ; no answer is checked at exit of testbound.
 SCENARIO_END
index 94f998be66a492f4c5968d70e26a303d6f5f0c90..894a7cc5fca3b220554cbec423e252653089a1e3 100644 (file)
@@ -20,6 +20,7 @@ $ORIGIN rpz.example.com.
 16.0.0.10.10.rpz-ip CNAME .
 24.0.10.10.10.rpz-ip CNAME rpz-drop.
 32.10.10.10.10.rpz-ip CNAME rpz-passthru.
+32.1.1.1.10.rpz-ip CNAME rpz-tcp-only.
 32.zz.db8.2001.rpz-ip CNAME *.
 48.zz.aa.db8.2001.rpz-ip CNAME .
 64.zz.bb.aa.db8.2001.rpz-ip CNAME rpz-drop.
@@ -217,6 +218,16 @@ SECTION ANSWER
 h. IN AAAA 2001:db8:aa:bb:cc::124
 ENTRY_END
 
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+y. IN A
+SECTION ANSWER
+y. IN A 10.1.1.1
+ENTRY_END
+
 RANGE_END
 
 STEP 1 QUERY
@@ -446,4 +457,21 @@ SECTION QUESTION
 e.     IN      AAAA
 ENTRY_END
 STEP 29 TIME_PASSES ELAPSE 12
+
+STEP 30 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+y.     IN      A
+ENTRY_END
+
+STEP 31 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR TC RD RA NOERROR
+SECTION QUESTION
+y.     IN      A
+SECTION ANSWER
+ENTRY_END
+
 SCENARIO_END