From: Ralph Dolmans Date: Mon, 24 Jun 2019 14:01:01 +0000 (+0200) Subject: Procedures to parse RPZ ip address notation. X-Git-Tag: release-1.10.0rc1~28^2~28^2~14 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=395d83cfc8bb86dfe47e2becb9885d13599998c1;p=thirdparty%2Funbound.git Procedures to parse RPZ ip address notation. --- diff --git a/services/rpz.c b/services/rpz.c index b19157b03..ef2d504ca 100644 --- a/services/rpz.c +++ b/services/rpz.c @@ -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", diff --git a/services/rpz.h b/services/rpz.h index 3bf7e43e0..64fac1ea4 100644 --- a/services/rpz.h +++ b/services/rpz.h @@ -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. */ diff --git a/util/data/dname.c b/util/data/dname.c index 8d8a5294c..cf3545f7c 100644 --- a/util/data/dname.c +++ b/util/data/dname.c @@ -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) { diff --git a/util/data/dname.h b/util/data/dname.h index 53a33c689..a7939fb6e 100644 --- a/util/data/dname.h +++ b/util/data/dname.h @@ -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. diff --git a/util/net_help.c b/util/net_help.c index 13bcdf808..9bc240c5d 100644 --- a/util/net_help.c +++ b/util/net_help.c @@ -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) { diff --git a/util/net_help.h b/util/net_help.h index 0b197fbdd..183d25951 100644 --- a/util/net_help.h +++ b/util/net_help.h @@ -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 */