diff options
| -rw-r--r-- | src/shared/dns-domain.c | 34 | ||||
| -rw-r--r-- | src/shared/dns-domain.h | 2 | ||||
| -rw-r--r-- | src/test/test-dns-domain.c | 31 | 
3 files changed, 67 insertions, 0 deletions
| diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c index 7af15e0098..423ccca9cc 100644 --- a/src/shared/dns-domain.c +++ b/src/shared/dns-domain.c @@ -715,3 +715,37 @@ int dns_name_single_label(const char *name) {          return r == 0 && *name == 0;  } + +/* Encode a domain name according to RFC 1035 Section 3.1 */ +int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len) { +        uint8_t *label_length; +        uint8_t *out; +        int r; + +        assert_return(buffer, -EINVAL); +        assert_return(domain, -EINVAL); +        assert_return(domain[0], -EINVAL); + +        out = buffer; + +        do { +                /* reserve a byte for label length */ +                if (len == 0) +                        return -ENOBUFS; +                len--; +                label_length = out; +                out++; + +                /* convert and copy a single label */ +                r = dns_label_unescape(&domain, (char *) out, len); +                if (r < 0) +                        return r; + +                /* fill label length, move forward */ +                *label_length = r; +                out += r; +                len -= r; +        } while (r != 0); + +        return out - buffer; +} diff --git a/src/shared/dns-domain.h b/src/shared/dns-domain.h index 1f0d242c18..b214897440 100644 --- a/src/shared/dns-domain.h +++ b/src/shared/dns-domain.h @@ -67,3 +67,5 @@ int dns_name_address(const char *p, int *family, union in_addr_union *a);  int dns_name_root(const char *name);  int dns_name_single_label(const char *name); + +int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len); diff --git a/src/test/test-dns-domain.c b/src/test/test-dns-domain.c index d5778748a0..407c7d8ef7 100644 --- a/src/test/test-dns-domain.c +++ b/src/test/test-dns-domain.c @@ -52,6 +52,36 @@ static void test_dns_label_unescape(void) {          test_dns_label_unescape_one("foobar.", "foobar", 20, 6);  } +static void test_dns_name_to_wire_format_one(const char *what, const char *expect, size_t buffer_sz, int ret) { +        uint8_t buffer[buffer_sz]; +        int r; + +        r = dns_name_to_wire_format(what, buffer, buffer_sz); +        assert_se(r == ret); + +        if (r < 0) +                return; + +        assert_se(!memcmp(buffer, expect, r)); +} + +static void test_dns_name_to_wire_format(void) { +        const char out1[] = { 3, 'f', 'o', 'o', 0 }; +        const char out2[] = { 5, 'h', 'a', 'l', 'l', 'o', 3, 'f', 'o', 'o', 3, 'b', 'a', 'r', 0 }; +        const char out3[] = { 4, ' ', 'f', 'o', 'o', 3, 'b', 'a', 'r', 0 }; + +        test_dns_name_to_wire_format_one("", NULL, 0, -EINVAL); + +        test_dns_name_to_wire_format_one("foo", out1, sizeof(out1), sizeof(out1)); +        test_dns_name_to_wire_format_one("foo", out1, sizeof(out1) + 1, sizeof(out1)); +        test_dns_name_to_wire_format_one("foo", out1, sizeof(out1) - 1, -ENOBUFS); + +        test_dns_name_to_wire_format_one("hallo.foo.bar", out2, sizeof(out2), sizeof(out2)); +        test_dns_name_to_wire_format_one("hallo.foo..bar", NULL, 32, -EINVAL); + +        test_dns_name_to_wire_format_one("\\032foo.bar", out3, sizeof(out3), sizeof(out3)); +} +  static void test_dns_label_unescape_suffix_one(const char *what, const char *expect1, const char *expect2, size_t buffer_sz, int ret1, int ret2) {          char buffer[buffer_sz];          const char *label; @@ -300,6 +330,7 @@ int main(int argc, char *argv[]) {          test_dns_name_reverse();          test_dns_name_concat();          test_dns_name_is_valid(); +        test_dns_name_to_wire_format();          return 0;  } | 
