]> git.meshlink.io Git - catta/commitdiff
add support for dots and backslashes in domain names (required for DNS-SD)
authorLennart Poettering <lennart@poettering.net>
Sun, 24 Apr 2005 20:23:07 +0000 (20:23 +0000)
committerLennart Poettering <lennart@poettering.net>
Sun, 24 Apr 2005 20:23:07 +0000 (20:23 +0000)
git-svn-id: file:///home/lennart/svn/public/avahi/trunk@28 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe

Makefile
dns-test.c [new file with mode: 0644]
dns.c
dns.h
domain-test.c [new file with mode: 0644]
psched.c
rr.c
server.c
util.c
util.h

index 58512868cf3f7d5b3edb1f0c3af39c72ad223b55..2a3be765e3ca20c0714e7cc092eaa0907ac30411 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 CFLAGS=-g -O0 -Wall -W -pipe $(shell pkg-config --cflags glib-2.0) -Wno-unused
 LIBS=$(shell pkg-config --libs glib-2.0)
 
-all: strlst-test prioq-test flexmdns 
+all: strlst-test prioq-test domain-test dns-test flexmdns
 
 flexmdns: timeeventq.o main.o iface.o netlink.o server.o address.o util.o prioq.o cache.o rr.o dns.o socket.o psched.o announce.o subscribe.o strlst.o
        $(CC) -o $@ $^ $(LIBS)
@@ -13,10 +13,15 @@ flexmdns: timeeventq.o main.o iface.o netlink.o server.o address.o util.o prioq.
 prioq-test: prioq-test.o prioq.o
        $(CC) -o $@ $^ $(LIBS)
 
-
 strlst-test: strlst-test.o strlst.o
        $(CC) -o $@ $^ $(LIBS)
 
+domain-test: domain-test.o util.o
+       $(CC) -o $@ $^ $(LIBS)
+
+dns-test: dns-test.o util.o dns.o rr.o strlst.o
+       $(CC) -o $@ $^ $(LIBS)
+
 
 *.o: *.h
 
diff --git a/dns-test.c b/dns-test.c
new file mode 100644 (file)
index 0000000..5d09b4a
--- /dev/null
@@ -0,0 +1,29 @@
+#include "dns.h"
+#include "util.h"
+
+int main(int argc, char *argv[]) {
+    gchar t[256];
+    flxDnsPacket *p;
+
+    p = flx_dns_packet_new(8000);
+
+    flx_dns_packet_append_name(p, "hello.hello.hello.de.");
+    flx_dns_packet_append_name(p, "this is a test.hello.de."); 
+    flx_dns_packet_append_name(p, "this\\.is\\.a\\.test\\.with\\.dots.hello.de."); 
+    flx_dns_packet_append_name(p, "this\\\\is another\\ \\test.hello.de."); 
+
+    flx_hexdump(FLX_DNS_PACKET_DATA(p), p->size);
+
+    flx_dns_packet_consume_name(p, t, sizeof(t));
+    g_message(">%s<", t);
+    flx_dns_packet_consume_name(p, t, sizeof(t));
+    g_message(">%s<", t);
+    flx_dns_packet_consume_name(p, t, sizeof(t));
+    g_message(">%s<", t);
+    flx_dns_packet_consume_name(p, t, sizeof(t));
+    g_message(">%s<", t);
+    
+    
+    flx_dns_packet_free(p);
+    return 0;
+}
diff --git a/dns.c b/dns.c
index 11eb005d83844060540e80bd0f37a2ceac168dac..f55ae78df2f8dda64c8b06b5da077d8f2f223a55 100644 (file)
--- a/dns.c
+++ b/dns.c
@@ -63,6 +63,48 @@ guint16 flx_dns_packet_get_field(flxDnsPacket *p, guint index) {
     return g_ntohs(((guint16*) FLX_DNS_PACKET_DATA(p))[index]);
 }
 
+/* Read the first label from string dest, unescape "\" and append it to *name */
+static gchar *unescape_label(gchar *dest, guint size, const gchar **name) {
+    guint i = 0;
+    gchar *d;
+    
+    g_assert(dest);
+    g_assert(size > 0);
+    g_assert(name);
+    g_assert(*name);
+
+    d = dest;
+    
+    for (;;) {
+        if (i >= size)
+            return NULL;
+
+        if (**name == '.') {
+            (*name)++;
+            break;
+        }
+        
+        if (**name == 0)
+            break;
+        
+        if (**name == '\\') {
+            (*name) ++;
+            
+            if (**name == 0)
+                break;
+        }
+        
+        *(d++) = *((*name) ++);
+        i++;
+    }
+
+    g_assert(i < size);
+
+    *d = 0;
+
+    return dest;
+}
+
 guint8* flx_dns_packet_append_name(flxDnsPacket *p, const gchar *name) {
     guint8 *d, *f = NULL;
     guint saved_size;
@@ -72,9 +114,11 @@ guint8* flx_dns_packet_append_name(flxDnsPacket *p, const gchar *name) {
 
     saved_size = p->size;
 
-    for (;;) {
+    while (*name) {
         guint n;
         guint8* prev;
+        const gchar *pname;
+        char label[64];
 
         /* Check whether we can compress this name. */
 
@@ -98,41 +142,25 @@ guint8* flx_dns_packet_append_name(flxDnsPacket *p, const gchar *name) {
                 return f;
             }
         }
+
+        pname = name;
         
-        n = strcspn(name, ".");
-        if (!n || n > 63)
-            goto fail;
-        
-        if (!(d = flx_dns_packet_extend(p, n+1)))
+        if (!(unescape_label(label, sizeof(label), &name)))
             goto fail;
-            
-        if (!f)
-            f = d;
-        d[0] = n;
-        memcpy(d+1, name, n);
 
+        if (!(d = flx_dns_packet_append_string(p, label)))
+            goto fail;
+        
         if (!p->name_table)
             p->name_table = g_hash_table_new_full((GHashFunc) flx_domain_hash, (GEqualFunc) flx_domain_equal, g_free, NULL);
 
-        g_hash_table_insert(p->name_table, g_strdup(name), d);
-
-        name += n;
-
-        /* no trailing dot */
-        if (!*name)
-            break;
-
-        name ++;
-
-        /* trailing dot */
-        if (!*name)
-            break;
+        g_hash_table_insert(p->name_table, g_strdup(pname), d);
     }
 
     if (!(d = flx_dns_packet_extend(p, 1)))
         goto fail;
     
-    d[0] = 0;
+    *d = 0;
 
     return f;
 
@@ -141,25 +169,6 @@ fail:
     return NULL;
 }
 
-guint8 *flx_dns_packet_append_name_compressed(flxDnsPacket *p, const gchar *name, guint8 *prev) {
-    guint16 *d;
-    signed long k;
-    g_assert(p);
-
-    if (!prev)
-        return flx_dns_packet_append_name(p, name);
-    
-    k = prev - FLX_DNS_PACKET_DATA(p);
-    if (k < 0 || k >= 0x4000 || (guint) k >= p->size)
-        return flx_dns_packet_append_name(p, name);
-
-    if (!(d = (guint16*) flx_dns_packet_extend(p, sizeof(guint16))))
-        return NULL;
-    
-    *d = g_htons((0xC000 | k));
-    return prev;
-}
-
 guint8* flx_dns_packet_append_uint16(flxDnsPacket *p, guint16 v) {
     guint8 *d;
     g_assert(p);
@@ -251,6 +260,42 @@ gint flx_dns_packet_is_query(flxDnsPacket *p) {
     return !(flx_dns_packet_get_field(p, FLX_DNS_FIELD_FLAGS) & FLX_DNS_FLAG_QR);
 }
 
+/* Read a label from a DNS packet, escape "\" and ".", append \0 */
+static gchar *escape_label(guint8* src, guint src_length, gchar **ret_name, guint *ret_name_length) {
+    gchar *r;
+
+    g_assert(src);
+    g_assert(ret_name);
+    g_assert(*ret_name);
+    g_assert(ret_name_length);
+    g_assert(*ret_name_length > 0);
+
+    r = *ret_name;
+
+    while (src_length > 0) {
+        if (*src == '.' || *src == '\\') {
+            if (*ret_name_length < 3)
+                return NULL;
+            
+            *((*ret_name) ++) = '\\';
+            (*ret_name_length) --;
+        }
+
+        if (*ret_name_length < 2)
+            return NULL;
+        
+        *((*ret_name)++) = *src;
+        (*ret_name_length) --;
+
+        src_length --;
+        src++;
+    }
+
+    **ret_name = 0;
+
+    return r;
+}
+
 static gint consume_labels(flxDnsPacket *p, guint index, gchar *ret_name, guint l) {
     gint ret = 0;
     int compressed = 0;
@@ -294,10 +339,10 @@ static gint consume_labels(flxDnsPacket *p, guint index, gchar *ret_name, guint
             } else
                 first_label = 0;
 
-            memcpy(ret_name, FLX_DNS_PACKET_DATA(p) + index, n);
+            if (!(escape_label(FLX_DNS_PACKET_DATA(p) + index, n, &ret_name, &l)))
+                return -1;
+
             index += n;
-            ret_name += n;
-            l -= n;
             
             if (!compressed)
                 ret += n;
diff --git a/dns.h b/dns.h
index 706b8c6fce4390b22f695e0d71d35a14025b1465..3a50bb0fb56feed77626becab922a65453c1b7ee 100644 (file)
--- a/dns.h
+++ b/dns.h
@@ -29,7 +29,6 @@ guint8 *flx_dns_packet_extend(flxDnsPacket *p, guint l);
 guint8 *flx_dns_packet_append_uint16(flxDnsPacket *p, guint16 v);
 guint8 *flx_dns_packet_append_uint32(flxDnsPacket *p, guint32 v);
 guint8 *flx_dns_packet_append_name(flxDnsPacket *p, const gchar *name);
-guint8 *flx_dns_packet_append_name_compressed(flxDnsPacket *p, const gchar *name, guint8 *prev);
 guint8 *flx_dns_packet_append_bytes(flxDnsPacket  *p, gconstpointer, guint l);
 guint8* flx_dns_packet_append_key(flxDnsPacket *p, flxKey *k);
 guint8* flx_dns_packet_append_record(flxDnsPacket *p, flxRecord *r, gboolean cache_flush);
diff --git a/domain-test.c b/domain-test.c
new file mode 100644 (file)
index 0000000..ab02943
--- /dev/null
@@ -0,0 +1,19 @@
+#include "util.h"
+
+int main(int argc, char *argv[]) {
+    gchar *s;
+    
+    g_message("host name: %s", s = flx_get_host_name());
+    g_free(s);
+
+    g_message("%s", s = flx_normalize_name("foo.foo."));
+    g_free(s);
+    
+    g_message("%s", s = flx_normalize_name("foo.foo."));
+    g_free(s);
+
+
+    g_message("%i", flx_domain_equal("\\aaa bbb\\.cccc\\\\.dee.fff.", "aaa\\ bbb\\.cccc\\\\.dee.fff"));
+
+    return 0;
+}
index e9f77b9e08e1d0bf7d622b673dc7a720fb455431..661a5f96d48a7ce840bf91f28678129120d8b26d 100644 (file)
--- a/psched.c
+++ b/psched.c
@@ -612,7 +612,7 @@ static guint8* packet_add_probe_query(flxPacketScheduler *s, flxDnsPacket *p, fl
             continue;
 
         /* Does the record match the probe? */
-        if (k->class != pj->record->key->class || strcmp(k->name, pj->record->key->name))
+        if (k->class != pj->record->key->class || flx_domain_equal(k->name, pj->record->key->name))
             continue;
         
         /* This job wouldn't fit in */
diff --git a/rr.c b/rr.c
index f72557b055ebf01101a00707cfad7c3cc5d82ff8..2c5a044e044c2651490fda416c8f038c08cd5637 100644 (file)
--- a/rr.c
+++ b/rr.c
@@ -214,7 +214,7 @@ gboolean flx_key_equal(const flxKey *a, const flxKey *b) {
 
 /*     g_message("equal: %p %p", a, b); */
     
-    return strcmp(a->name, b->name) == 0 &&
+    return flx_domain_equal(a->name, b->name) == 0 &&
         a->type == b->type &&
         a->class == b->class;
 }
@@ -227,7 +227,7 @@ gboolean flx_key_pattern_match(const flxKey *pattern, const flxKey *k) {
 
     g_assert(!flx_key_is_pattern(k));
     
-    return strcmp(pattern->name, k->name) == 0 &&
+    return flx_domain_equal(pattern->name, k->name) == 0 &&
         (pattern->type == k->type || pattern->type == FLX_DNS_TYPE_ANY) &&
         pattern->class == k->class;
 }
@@ -242,7 +242,7 @@ gboolean flx_key_is_pattern(const flxKey *k) {
 guint flx_key_hash(const flxKey *k) {
     g_assert(k);
 
-    return g_str_hash(k->name) + k->type + k->class;
+    return flx_domain_hash(k->name) + k->type + k->class;
 }
 
 static gboolean rdata_equal(const flxRecord *a, const flxRecord *b) {
@@ -265,11 +265,11 @@ static gboolean rdata_equal(const flxRecord *a, const flxRecord *b) {
                 a->data.srv.priority == b->data.srv.priority &&
                 a->data.srv.weight == b->data.srv.weight &&
                 a->data.srv.port == b->data.srv.port &&
-                !strcmp(a->data.srv.name, b->data.srv.name);
+                flx_domain_equal(a->data.srv.name, b->data.srv.name);
 
         case FLX_DNS_TYPE_PTR:
         case FLX_DNS_TYPE_CNAME:
-            return !strcmp(a->data.ptr.name, b->data.ptr.name);
+            return flx_domain_equal(a->data.ptr.name, b->data.ptr.name);
 
         case FLX_DNS_TYPE_HINFO:
             return
index 56e4d813600b53cd656866e1d84a390d98d5828f..cd97262afed8e6f80a4e8c105243c9f310b8b9d5 100644 (file)
--- a/server.c
+++ b/server.c
@@ -300,10 +300,9 @@ flxServer *flx_server_new(GMainContext *c) {
     
     /* Get host name */
     hn = flx_get_host_name();
-    if ((e = strchr(hn, '.')))
-        *e = 0;
+    hn[strcspn(hn, ".")] = 0;
 
-    s->hostname = g_strdup_printf("%s.local.", hn);
+    s->hostname = g_strdup_printf("%slocal.", hn);
     g_free(hn);
 
     add_default_entries(s);
diff --git a/util.c b/util.c
index 0fcedc71c0fee844ba99015c4b5a6fcd421bb883..2cd0a87938761b0ac021a53f86be3ca759bff5f9 100644 (file)
--- a/util.c
+++ b/util.c
@@ -2,13 +2,20 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <errno.h>
+#include <limits.h>
+#include <stdio.h>
 
 #include "util.h"
 
 gchar *flx_get_host_name(void) {
+#ifdef HOST_NAME_MAX
+    char t[HOST_NAME_MAX];
+#else
     char t[256];
+#endif
     gethostname(t, sizeof(t));
-    return g_strndup(t, sizeof(t));
+    t[sizeof(t)-1] = 0;
+    return flx_normalize_name(t);
 }
 
 gchar *flx_normalize_name(const gchar *s) {
@@ -127,24 +134,37 @@ gint flx_age(const GTimeVal *a) {
 }
 
 gboolean flx_domain_equal(const gchar *a, const gchar *b) {
+    int escaped_a = 0, escaped_b = 0;
     g_assert(a);
     g_assert(b);
 
     for (;;) {
+        /* Check for escape characters "\" */
+        if ((escaped_a = *a == '\\'))
+            a ++;
+
+        if ((escaped_b = *b == '\\'))
+            b++;
+
+        /* Check for string end */
         if (*a == 0 && *b == 0)
             return TRUE;
         
-        if (*a == 0 && *b == '.' && *(b+1) == 0)
+        if (*a == 0 && !escaped_b && *b == '.' && *(b+1) == 0)
             return TRUE;
 
-        if (*a == '.' && *(a+1) == 0 && *b == 0)
+        if (!escaped_a && *a == '.' && *(a+1) == 0 && *b == 0)
             return TRUE;
 
-        if (*a != *b)
+        /* Compare characters */
+        if (escaped_a == escaped_b && *a != *b)
             return FALSE;
 
+
+        /* Next characters */
         a++;
         b++;
+        
     }
 }
 
@@ -156,3 +176,36 @@ guint flx_domain_hash(const gchar *p) {
     return g_int_hash(t);
 }
 
+void flx_hexdump(gconstpointer p, guint size) {
+    const guint8 *c = p;
+    g_assert(p);
+
+    printf("Dumping %u bytes from %p:\n", size, p);
+    
+    while (size > 0) {
+        guint i;
+
+        for (i = 0; i < 16; i++) { 
+            if (i < size)
+                printf("%02x ", c[i]);
+            else
+                printf("   ");
+        }
+
+        for (i = 0; i < 16; i++) {
+            if (i < size)
+                printf("%c", c[i] >= 32 && c[i] < 127 ? c[i] : '.');
+            else
+                printf(" ");
+        }
+        
+        printf("\n");
+
+        c += 16;
+
+        if (size <= 16)
+            break;
+        
+        size -= 16;
+    }
+}
diff --git a/util.h b/util.h
index 53884cb38242925e8e563d7582f46315bb2f1b28..335ab820ab255135783ead48ced5bfa1c1c0434d 100644 (file)
--- a/util.h
+++ b/util.h
@@ -20,4 +20,6 @@ gint flx_age(const GTimeVal *a);
 guint flx_domain_hash(const gchar *p);
 gboolean flx_domain_equal(const gchar *a, const gchar *b);
 
+void flx_hexdump(gconstpointer p, guint size);
+
 #endif