shared: add new dns_name_startswith() call
authorLennart Poettering <lennart@poettering.net>
Wed, 13 Jan 2016 01:23:08 +0000 (02:23 +0100)
committerLennart Poettering <lennart@poettering.net>
Wed, 13 Jan 2016 19:21:56 +0000 (20:21 +0100)
dns_name_startswith() is to dns_name_endswith() as startswith() is to endswith().

src/shared/dns-domain.c
src/shared/dns-domain.h
src/test/test-dns-domain.c

index 5947511..e777bad 100644 (file)
@@ -263,7 +263,6 @@ int dns_label_escape(const char *p, size_t l, char *dest, size_t sz) {
                         *(q++) = '0' + (char) ((uint8_t) *p % 10);
 
                         sz -= 4;
-
                 }
 
                 p++;
@@ -653,6 +652,54 @@ int dns_name_endswith(const char *name, const char *suffix) {
         }
 }
 
+static int dns_label_unescape_undo_idna(const char **name, char *dest, size_t sz) {
+        int r, k;
+
+        /* Clobbers all arguments on failure... */
+
+        r = dns_label_unescape(name, dest, sz);
+        if (r <= 0)
+                return r;
+
+        k = dns_label_undo_idna(dest, r, dest, sz);
+        if (k < 0)
+                return k;
+        if (k == 0) /* not an IDNA name */
+                return r;
+
+        return k;
+}
+
+int dns_name_startswith(const char *name, const char *prefix) {
+        const char *n, *p;
+        int r, q;
+
+        assert(name);
+        assert(prefix);
+
+        n = name;
+        p = prefix;
+
+        for (;;) {
+                char ln[DNS_LABEL_MAX], lp[DNS_LABEL_MAX];
+
+                r = dns_label_unescape_undo_idna(&p, lp, sizeof(lp));
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return true;
+
+                q = dns_label_unescape_undo_idna(&n, ln, sizeof(ln));
+                if (q < 0)
+                        return q;
+
+                if (r != q)
+                        return false;
+                if (ascii_strcasecmp_n(ln, lp, r) != 0)
+                        return false;
+        }
+}
+
 int dns_name_change_suffix(const char *name, const char *old_suffix, const char *new_suffix, char **ret) {
         const char *n, *s, *saved_before = NULL, *saved_after = NULL, *prefix;
         int r, q, k, w;
index dd8ae3a..4fbe0a6 100644 (file)
@@ -83,6 +83,7 @@ extern const struct hash_ops dns_name_hash_ops;
 int dns_name_between(const char *a, const char *b, const char *c);
 int dns_name_equal(const char *x, const char *y);
 int dns_name_endswith(const char *name, const char *suffix);
+int dns_name_startswith(const char *name, const char *prefix);
 
 int dns_name_change_suffix(const char *name, const char *old_suffix, const char *new_suffix, char **ret);
 
index 6c3c499..fe3ae45 100644 (file)
@@ -276,6 +276,25 @@ static void test_dns_name_endswith(void) {
         test_dns_name_endswith_one("x.y\001.z", "waldo", -EINVAL);
 }
 
+static void test_dns_name_startswith_one(const char *a, const char *b, int ret) {
+        assert_se(dns_name_startswith(a, b) == ret);
+}
+
+static void test_dns_name_startswith(void) {
+        test_dns_name_startswith_one("", "", true);
+        test_dns_name_startswith_one("", "xxx", false);
+        test_dns_name_startswith_one("xxx", "", true);
+        test_dns_name_startswith_one("x", "x", true);
+        test_dns_name_startswith_one("x", "y", false);
+        test_dns_name_startswith_one("x.y", "x.y", true);
+        test_dns_name_startswith_one("x.y", "y.x", false);
+        test_dns_name_startswith_one("x.y", "x", true);
+        test_dns_name_startswith_one("x.y", "X", true);
+        test_dns_name_startswith_one("x.y", "y", false);
+        test_dns_name_startswith_one("x.y", "", true);
+        test_dns_name_startswith_one("x.y", "X", true);
+}
+
 static void test_dns_name_is_root(void) {
         assert_se(dns_name_is_root(""));
         assert_se(dns_name_is_root("."));
@@ -567,6 +586,7 @@ int main(int argc, char *argv[]) {
         test_dns_name_normalize();
         test_dns_name_equal();
         test_dns_name_endswith();
+        test_dns_name_startswith();
         test_dns_name_between();
         test_dns_name_is_root();
         test_dns_name_is_single_label();