]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
Procedures to parse RPZ ip address notation.
authorRalph Dolmans <ralph@nlnetlabs.nl>
Mon, 24 Jun 2019 14:01:01 +0000 (16:01 +0200)
committerRalph Dolmans <ralph@nlnetlabs.nl>
Mon, 24 Jun 2019 14:01:01 +0000 (16:01 +0200)
services/rpz.c
services/rpz.h
util/data/dname.c
util/data/dname.h
util/net_help.c
util/net_help.h

index b19157b03fdcce54c5501dc9b2282fe2808a41af..ef2d504ca98f6128fb056642fdb6b985c28de079 100644 (file)
@@ -436,6 +436,48 @@ rpz_insert_qname_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
        return 1;
 }
 
+/** Insert RR into RPZ's ACL tree */
+static int
+rpz_insert_client_ip_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
+       enum rpz_action a, uint16_t rrtype, uint16_t rrclass, uint32_t ttl,
+       uint8_t* rdata, size_t rdata_len, uint8_t* rr, size_t rr_len)
+{
+       /* TODO: remove void casts */
+       (void)r;
+       (void)dnamelen;
+       (void)rrtype;
+       (void)rrclass;
+       (void)ttl;
+       (void)rdata;
+       (void)rdata_len;
+       (void)rr;
+       (void)rr_len;
+
+       if(a == RPZ_DROP_ACTION) {
+               /* insert into r->acl tree */
+               struct sockaddr_storage addr;
+               char str[INET6_ADDRSTRLEN];
+               socklen_t addrlen;
+               int net, af;
+               if(!netblockdnametoaddr(dname, &addr, &addrlen, &net, &af))
+                       return 0;
+               /* TODO insert into acl tree */
+#if 0
+               if((inet_ntop(af,
+                       (af == AF_INET) ?
+                               (void*)&((struct sockaddr_in*)&addr)->sin_addr :
+                               (void*)&((struct sockaddr_in6*)&addr)->sin6_addr,
+                       str, INET6_ADDRSTRLEN)))
+                       log_info("rpz %s/%d\n", str, net);
+#endif
+       } else {
+               verbose(VERB_ALGO, "RPZ: skipping unsupported action: %s",
+                       rpz_action_to_string(a));
+               return 0;
+       }
+       return 0;
+}
+
 void
 rpz_insert_rr(struct rpz* r, size_t aznamelen, uint8_t* dname,
        size_t dnamelen, uint16_t rr_type, uint16_t rr_class, uint32_t rr_ttl,
@@ -459,6 +501,11 @@ rpz_insert_rr(struct rpz* r, size_t aznamelen, uint8_t* dname,
                        a, rr_type, rr_class, rr_ttl, rdatawl, rdatalen, rr,
                        rr_len);
        }
+       else if(t == RPZ_CLIENT_IP_TRIGGER) {
+               rpz_insert_client_ip_trigger(r, policydname, policydnamelen,
+                       a, rr_type, rr_class, rr_ttl, rdatawl, rdatalen, rr,
+                       rr_len);
+       }
        else {
                free(policydname);
                verbose(VERB_ALGO, "RPZ: skipping unusupported trigger: %s",
index 3bf7e43e063a24d60430b36e9882992d57b3909f..64fac1ea475aa469a5e7f5d6ca5b4a8f186b1b55 100644 (file)
@@ -81,7 +81,7 @@ enum rpz_action {
 };
 
 /**
- * RPZ containing policies. Pointed to from corresponding authz-one. Part of a
+ * RPZ containing policies. Pointed to from corresponding auth-zone. Part of a
  * linked list to keep configuration order. Iterating or changing the linked
  * list requires the rpz_lock from struct auth_zones.
  */
index 8d8a5294ca98db330c64c15ed5a41a1f95399c23..cf3545f7c37c8025a7c9bcad79bcf0eef0e6873b 100644 (file)
@@ -546,6 +546,19 @@ dname_lab_startswith(uint8_t* label, char* prefix, char** endptr)
        return 1;
 }
 
+int
+dname_has_label(uint8_t* dname, uint8_t* label)
+{
+       uint8_t lablen = *dname++;
+       while(lablen) {
+               if(*label == lablen && memcmp(dname, label+1, lablen) == 0)
+                       return 1;
+               dname += lablen;
+               lablen = *dname++;
+       }
+       return 0;
+}
+
 int 
 dname_buffer_write(sldns_buffer* pkt, uint8_t* dname)
 {
index 53a33c689bc0b760dfcc033a0f1f192ae4dfd50f..a7939fb6e8bef9f8bfaf77374e9e67c9eacbc634 100644 (file)
@@ -196,6 +196,14 @@ int dname_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs);
  */
 int dname_lab_startswith(uint8_t* label, char* prefix, char** endptr);
 
+/**
+ * Check if dname contains label
+ * @param dname: dname
+ * @param label: label to be checked for presence in dname
+ * @return: 1 if dname has this label, 0 otherwise
+ */
+int dname_has_label(uint8_t* dname, uint8_t* label);
+
 /**
  * See if domain name d1 is a strict subdomain of d2.
  * That is a subdomain, but not equal. 
index 13bcdf8085bff3546bd3b055ce3d57c7d9370359..9bc240c5d9e941efc1b25c2dbe18346bff90f818 100644 (file)
@@ -284,6 +284,93 @@ int netblockstrtoaddr(const char* str, int port, struct sockaddr_storage* addr,
        return 1;
 }
 
+/* RPZ format address dname to network byte order address */
+static int ipdnametoaddr(uint8_t* dname, struct sockaddr_storage* addr,
+       socklen_t* addrlen, int* af)
+{
+       uint8_t* ia;
+       size_t dnamelabs = dname_count_labels(dname);
+       uint8_t lablen;
+       char* e = NULL;
+       int z = 0;
+       int i;
+       *af = AF_INET;
+       if(dnamelabs > 6 || dname_has_label(dname, (uint8_t*)"\002zz")) {
+               *af = AF_INET6;
+       }
+       lablen = *dname++;
+       i = (*af == AF_INET) ? 3 : 15;
+       if(*af == AF_INET6) {
+               struct sockaddr_in6* sa = (struct sockaddr_in6*)addr;
+               *addrlen = (socklen_t)sizeof(struct sockaddr_in6);
+               memset(sa, 0, *addrlen);
+               sa->sin6_family = AF_INET6;
+               ia = (uint8_t*)&sa->sin6_addr;
+       } else { /* ip4 */
+               struct sockaddr_in* sa = (struct sockaddr_in*)addr;
+               *addrlen = (socklen_t)sizeof(struct sockaddr_in);
+               memset(sa, 0, *addrlen);
+               sa->sin_family = AF_INET;
+               ia = (uint8_t*)&sa->sin_addr;
+       }
+       while(lablen && i >= 0) {
+               char buff[lablen+1];
+               uint16_t chunk; /* big enough to not overflow on IPv6 hextet */
+               if((*af == AF_INET && (lablen > 3 || dnamelabs > 6)) ||
+                       (*af == AF_INET6 && (lablen > 4 || dnamelabs > 10))) {
+                       return 0;
+               }
+               if(memcmp(dname, "zz", 2) == 0 && *af == AF_INET6) {
+                       /* add one or more 0 labels */
+                       int zl = 11 - dnamelabs;
+                       if(z || zl < 0)
+                               return 0;
+                       z = 1;
+                       i -= (zl*2);
+                       memset(ia+(i+1), 0, zl*2);
+               } else {
+                       memcpy(buff, dname, lablen);
+                       buff[lablen] = '\0';
+                       chunk = strtol(buff, &e, (*af == AF_INET) ? 10 : 16);
+                       if(!e || *e != '\0' || (*af == AF_INET && chunk > 255))
+                               return 0;
+                       if(*af == AF_INET) {
+                               ia[i] = (uint8_t)chunk;
+                               i--;
+                       } else {
+                               /* ia in network byte order */
+                               ia[i-1] = (uint8_t)(chunk >> 8);
+                               ia[i] = (uint8_t)(chunk & 0x00FF);
+                               i -= 2;
+                       }
+               }
+               dname += lablen;
+               lablen = *dname++;
+       }
+       if(i != -1)
+               /* input too short */
+               return 0;
+       return 1;
+}
+
+int netblockdnametoaddr(uint8_t* dname, struct sockaddr_storage* addr,
+       socklen_t* addrlen, int* net, int* af)
+{
+       int e;
+       char buff[3 /* 3 digit netblock */ + 1];
+       if(*dname > 3)
+               /* netblock invalid */
+               return 0;
+       memcpy(buff, dname+1, *dname);
+       buff[(*dname)+1] = '\0';
+       *net = atoi(buff);
+       dname += *dname;
+       dname++;
+       if(!ipdnametoaddr(dname, addr, addrlen, af))
+               return 0;
+       return 1;
+}
+
 int authextstrtoaddr(char* str, struct sockaddr_storage* addr, 
        socklen_t* addrlen, char** auth_name)
 {
index 0b197fbdd6e73e411ae11c0579d7be60ef31ef15..183d25951a7f857b6bf03965fc6fab4aa2db22c3 100644 (file)
@@ -464,4 +464,14 @@ int tls_session_ticket_key_cb(void *s, unsigned char* key_name,unsigned char* iv
 /** Free memory used for TLS session ticket keys */
 void listen_sslctx_delete_ticket_keys(void);
 
+/**
+ * RPZ format netblock to network byte order address and netblock
+ * @param dname: the dname containing RPZ format netblock
+ * @param addr: where to store sockaddr.
+ * @param addrlen: length of stored sockaddr is returned.
+ * @param af: where to store address family.
+ * @return 0 on error.
+ */
+int netblockdnametoaddr(uint8_t* dname, struct sockaddr_storage* addr,
+       socklen_t* addrlen, int* net, int* af);
 #endif /* NET_HELP_H */