diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/resolve/resolved-dns-packet.c | 178 | ||||
| -rw-r--r-- | src/resolve/resolved-dns-rr.c | 53 | ||||
| -rw-r--r-- | src/resolve/resolved-dns-rr.h | 6 | 
3 files changed, 237 insertions, 0 deletions
| diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index 1ebebf8ea4..d2b3cb0eb1 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -502,6 +502,89 @@ fail:          return r;  } +static int dns_packet_append_type_window(DnsPacket *p, uint8_t window, uint8_t length, uint8_t *types, size_t *start) { +        size_t saved_size; +        int r; + +        assert(p); +        assert(types); + +        if (length == 0) +                return 0; + +        saved_size = p->size; + +        r = dns_packet_append_uint8(p, window, NULL); +        if (r < 0) +                goto fail; + +        r = dns_packet_append_uint8(p, length, NULL); +        if (r < 0) +                goto fail; + +        r = dns_packet_append_blob(p, types, length, NULL); +        if (r < 0) +                goto fail; + +        if (start) +                *start = saved_size; + +        return 0; +fail: +        dns_packet_truncate(p, saved_size); +        return r; +} + +static int dns_packet_append_types(DnsPacket *p, Bitmap *types, size_t *start) { +        uint8_t window = 0; +        uint8_t len = 0; +        uint8_t bitmaps[32] = {}; +        unsigned n; +        size_t saved_size; +        int r; + +        assert(p); +        assert(types); + +        saved_size = p->size; + +        BITMAP_FOREACH(n, types) { +                uint8_t entry; + +                assert(n <= 0xffff); + +                if ((n << 8) != window) { +                        r = dns_packet_append_type_window(p, window, len, bitmaps, NULL); +                        if (r < 0) +                                goto fail; + +                        if (len > 0) { +                                len = 0; +                                zero(bitmaps); +                        } +                } + +                window = n << 8; +                len ++; + +                entry = n & 255; + +                bitmaps[entry / 8] |= 1 << (7 - (entry % 8)); +        } + +        r = dns_packet_append_type_window(p, window, len, bitmaps, NULL); +        if (r < 0) +                goto fail; + +        if (start) +                *start = saved_size; + +        return 0; +fail: +        dns_packet_truncate(p, saved_size); +        return r; +} +  int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start) {          size_t saved_size, rdlength_offset, end, rdlength;          int r; @@ -732,6 +815,16 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star                  r = dns_packet_append_blob(p, rr->rrsig.signature, rr->rrsig.signature_size, NULL);                  break; +        case DNS_TYPE_NSEC: +                r = dns_packet_append_name(p, rr->nsec.next_domain_name, false, NULL); +                if (r < 0) +                        goto fail; + +                r = dns_packet_append_types(p, rr->nsec.types, NULL); +                if (r < 0) +                        goto fail; + +                break;          case _DNS_TYPE_INVALID: /* unparseable */          default: @@ -996,6 +1089,79 @@ fail:          return r;  } +static int dns_packet_read_type_window(DnsPacket *p, Bitmap **types, size_t *start) { +        uint8_t window; +        uint8_t length; +        const uint8_t *bitmap; +        unsigned i; +        bool found = false; +        size_t saved_rindex; +        int r; + +        assert(p); +        assert(types); + +        saved_rindex = p->rindex; + +        r = bitmap_ensure_allocated(types); +        if (r < 0) +                goto fail; + +        r = dns_packet_read_uint8(p, &window, NULL); +        if (r < 0) +                goto fail; + +        r = dns_packet_read_uint8(p, &length, NULL); +        if (r < 0) +                goto fail; + +        if (length == 0 || length > 32) +                return -EBADMSG; + +        r = dns_packet_read(p, length, (const void **)&bitmap, NULL); +        if (r < 0) +                goto fail; + +        for (i = 0; i < length; i++) { +                uint8_t bitmask = 1 << 7; +                uint8_t bit = 0; + +                if (!bitmap[i]) { +                        found = false; +                        continue; +                } + +                found = true; + +                while (bitmask) { +                        if (bitmap[i] & bitmask) { +                                uint16_t n; + +                                /* XXX: ignore pseudo-types? see RFC4034 section 4.1.2 */ +                                n = (uint16_t) window << 8 | (uint16_t) bit; + +                                r = bitmap_set(*types, n); +                                if (r < 0) +                                        goto fail; +                        } + +                        bit ++; +                        bitmask >>= 1; +                } +        } + +        if (!found) +                return -EBADMSG; + +        if (start) +                *start = saved_rindex; + +        return 0; +fail: +        dns_packet_rewind(p, saved_rindex); +        return r; +} +  int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, size_t *start) {          _cleanup_free_ char *name = NULL;          uint16_t class, type; @@ -1382,6 +1548,18 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {                                                 NULL);                  break; +        case DNS_TYPE_NSEC: +                r = dns_packet_read_name(p, &rr->nsec.next_domain_name, false, NULL); +                if (r < 0) +                        goto fail; + +                while (p->rindex != offset + rdlength) { +                        r = dns_packet_read_type_window(p, &rr->nsec.types, NULL); +                        if (r < 0) +                                goto fail; +                } + +                break;          default:          unparseable:                  r = dns_packet_read(p, rdlength, &d, NULL); diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index 676b77713e..48fb3538ae 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -288,6 +288,11 @@ DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {                          free(rr->rrsig.signature);                          break; +                case DNS_TYPE_NSEC: +                        free(rr->nsec.next_domain_name); +                        bitmap_free(rr->nsec.types); +                        break; +                  case DNS_TYPE_LOC:                  case DNS_TYPE_A:                  case DNS_TYPE_AAAA: @@ -448,6 +453,10 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor                  return dns_name_equal(a->rrsig.signer, b->rrsig.signer); +        case DNS_TYPE_NSEC: +                return dns_name_equal(a->nsec.next_domain_name, b->nsec.next_domain_name) && +                       bitmap_equal(a->nsec.types, b->nsec.types); +          default:                  return a->generic.size == b->generic.size &&                          memcmp(a->generic.data, b->generic.data, a->generic.size) == 0; @@ -500,6 +509,37 @@ static int format_timestamp_dns(char *buf, size_t l, time_t sec) {          return 0;  } +static char *format_types(Bitmap *types) { +        _cleanup_strv_free_ char **strv = NULL; +        _cleanup_free_ char *str = NULL; +        unsigned type; +        int r; + +        BITMAP_FOREACH(type, types) { +                if (dns_type_to_string(type)) { +                        r = strv_extend(&strv, strdup(dns_type_to_string(type))); +                        if (r < 0) +                                return NULL; +                } else { +                        char *t; + +                        r = asprintf(&t, "TYPE%u", type); +                        if (r < 0) +                                return NULL; + +                        r = strv_extend(&strv, t); +                        if (r < 0) +                                return NULL; +                } +        } + +        str = strv_join(strv, " "); +        if (!str) +                return NULL; + +        return strjoin("( ", str, " )", NULL); +} +  int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {          _cleanup_free_ char *k = NULL, *t = NULL;          char *s; @@ -704,6 +744,19 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {                  break;          } +        case DNS_TYPE_NSEC: +                t = format_types(rr->nsec.types); +                if (!t) +                        return -ENOMEM; + +                r = asprintf(&s, "%s %s %s", +                             k, +                             rr->nsec.next_domain_name, +                             t); +                if (r < 0) +                        return -ENOMEM; +                break; +          default:                  t = hexmem(rr->generic.data, rr->generic.size);                  if (!t) diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h index b375d6b9fc..eaaafb1f25 100644 --- a/src/resolve/resolved-dns-rr.h +++ b/src/resolve/resolved-dns-rr.h @@ -23,6 +23,7 @@  #include <netinet/in.h> +#include "bitmap.h"  #include "hashmap.h"  #include "in-addr-util.h"  #include "dns-type.h" @@ -145,6 +146,11 @@ struct DnsResourceRecord {                          void *signature;                          size_t signature_size;                  } rrsig; + +                struct { +                        char *next_domain_name; +                        Bitmap *types; +                } nsec;          };  }; | 
