From a20c01bd12216d409e0dfc5d3bbacc940352bfce Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 12 Apr 2005 03:09:56 +0000 Subject: [PATCH] assorted work: * new rr implementation: resource data is stored in parsed form now. * make TXT and SRV functions variadic * many other things git-svn-id: file:///home/lennart/svn/public/avahi/trunk@23 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe --- Makefile | 10 +- announce.c | 7 +- dns.c | 256 +++++++++++++++++++++++++++++++++++++++++--------- dns.h | 2 + flx.h | 45 +++++++-- main.c | 2 +- rr.c | 233 ++++++++++++++++++++++++++++++--------------- rr.h | 52 ++++++++-- server.c | 255 +++++++++++++++++++++++++++++++++++-------------- strlst-test.c | 46 +++++++++ strlst.c | 215 ++++++++++++++++++++++++++++++++++++++++++ strlst.h | 32 +++++++ todo | 4 +- 13 files changed, 946 insertions(+), 213 deletions(-) create mode 100644 strlst-test.c create mode 100644 strlst.c create mode 100644 strlst.h diff --git a/Makefile b/Makefile index 8f60172..5851286 100644 --- a/Makefile +++ b/Makefile @@ -2,9 +2,9 @@ CFLAGS=-g -O0 -Wall -W -pipe $(shell pkg-config --cflags glib-2.0) -Wno-unused LIBS=$(shell pkg-config --libs glib-2.0) -all: flexmdns prioq-test +all: strlst-test prioq-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 +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) #test-llist: test-llist.o @@ -14,7 +14,11 @@ prioq-test: prioq-test.o prioq.o $(CC) -o $@ $^ $(LIBS) +strlst-test: strlst-test.o strlst.o + $(CC) -o $@ $^ $(LIBS) + + *.o: *.h clean: - rm -f *.o flexmdns prioq-test + rm -f *.o flexmdns prioq-test strlst-test diff --git a/announce.c b/announce.c index 9229753..1671758 100644 --- a/announce.c +++ b/announce.c @@ -116,13 +116,18 @@ void flx_announce_entry(flxServer *s, flxServerEntry *e) { static flxRecord *make_goodbye_record(flxRecord *r) { gchar *t; + flxRecord *g; g_assert(r); g_message("Preparing goodbye for record [%s]", t = flx_record_to_string(r)); g_free(t); - return flx_record_new(r->key, r->data, r->size, 0); + g = flx_record_copy(r); + g_assert(g->ref == 1); + g->ttl = 0; + + return g; } void flx_goodbye_interface(flxServer *s, flxInterface *i, gboolean goodbye) { diff --git a/dns.c b/dns.c index bed7344..776ead2 100644 --- a/dns.c +++ b/dns.c @@ -1,3 +1,5 @@ +#include + #include #include #include @@ -139,6 +141,25 @@ guint8 *flx_dns_packet_append_bytes(flxDnsPacket *p, gconstpointer b, guint l) return d; } +guint8* flx_dns_packet_append_string(flxDnsPacket *p, const gchar *s) { + guint8* d; + guint k; + + g_assert(p); + g_assert(s); + + if ((k = strlen(s)) >= 255) + k = 255; + + if (!(d = flx_dns_packet_extend(p, k+1))) + return NULL; + + *d = (guint8) k; + memcpy(d+1, s, k); + + return d; +} + guint8 *flx_dns_packet_extend(flxDnsPacket *p, guint l) { guint8 *d; @@ -310,10 +331,38 @@ gint flx_dns_packet_consume_bytes(flxDnsPacket *p, gpointer ret_data, guint l) { return 0; } +gint flx_dns_packet_consume_string(flxDnsPacket *p, gchar *ret_string, guint l) { + guint k; + + g_assert(p); + g_assert(ret_string); + g_assert(l > 0); + + if (p->rindex >= p->size) + return -1; + + k = FLX_DNS_PACKET_DATA(p)[p->rindex]; + + if (p->rindex+1+k > p->size) + return -1; + + if (l > k+1) + l = k+1; + + memcpy(ret_string, FLX_DNS_PACKET_DATA(p)+p->rindex+1, l-1); + ret_string[l-1] = 0; + + + p->rindex += 1+k; + + return 0; + +} + gconstpointer flx_dns_packet_get_rptr(flxDnsPacket *p) { g_assert(p); - if (p->rindex >= p->size) + if (p->rindex > p->size) return NULL; return FLX_DNS_PACKET_DATA(p) + p->rindex; @@ -330,65 +379,144 @@ gint flx_dns_packet_skip(flxDnsPacket *p, guint length) { } flxRecord* flx_dns_packet_consume_record(flxDnsPacket *p, gboolean *ret_cache_flush) { - gchar name[257], buf[257+6]; + gchar name[257], buf[257]; guint16 type, class; guint32 ttl; guint16 rdlength; gconstpointer data; + flxRecord *r = NULL; + gconstpointer start; g_assert(p); g_assert(ret_cache_flush); + g_message("consume_record()"); + if (flx_dns_packet_consume_name(p, name, sizeof(name)) < 0 || flx_dns_packet_consume_uint16(p, &type) < 0 || flx_dns_packet_consume_uint16(p, &class) < 0 || flx_dns_packet_consume_uint32(p, &ttl) < 0 || - flx_dns_packet_consume_uint16(p, &rdlength) < 0) - return NULL; + flx_dns_packet_consume_uint16(p, &rdlength) < 0 || + p->rindex + rdlength > p->size) + + goto fail; + + g_message("name = %s, rdlength = %u", name, rdlength); + + start = flx_dns_packet_get_rptr(p); + r = flx_record_new_full(name, class, type); + switch (type) { case FLX_DNS_TYPE_PTR: case FLX_DNS_TYPE_CNAME: + + g_message("ptr"); + if (flx_dns_packet_consume_name(p, buf, sizeof(buf)) < 0) - return NULL; + goto fail; + + r->data.ptr.name = g_strdup(buf); + break; + - data = buf; - rdlength = strlen(buf); + case FLX_DNS_TYPE_SRV: + + g_message("srv"); + + if (flx_dns_packet_consume_uint16(p, &r->data.srv.priority) < 0 || + flx_dns_packet_consume_uint16(p, &r->data.srv.weight) < 0 || + flx_dns_packet_consume_uint16(p, &r->data.srv.port) < 0 || + flx_dns_packet_consume_name(p, buf, sizeof(buf)) < 0) + goto fail; + + r->data.srv.name = g_strdup(buf); + break; + + case FLX_DNS_TYPE_HINFO: + + g_message("hinfo"); + + if (flx_dns_packet_consume_string(p, buf, sizeof(buf)) < 0) + goto fail; + + r->data.hinfo.cpu = g_strdup(buf); + + if (flx_dns_packet_consume_string(p, buf, sizeof(buf)) < 0) + goto fail; + + r->data.hinfo.os = g_strdup(buf); break; - case FLX_DNS_TYPE_SRV: { - const guint8 *t = flx_dns_packet_get_rptr(p); + case FLX_DNS_TYPE_TXT: + + g_message("txt"); - if (flx_dns_packet_skip(p, 6) < 0) - return NULL; + if (rdlength > 0) { + r->data.txt.string_list = flx_string_list_parse(flx_dns_packet_get_rptr(p), rdlength); + + if (flx_dns_packet_skip(p, rdlength) < 0) + goto fail; + } - memcpy(buf, t, 6); + break; + + case FLX_DNS_TYPE_A: + + g_message("A"); - if (flx_dns_packet_consume_name(p, buf+6, sizeof(buf)-6) < 0) - return NULL; - data = buf; - rdlength = 6 + strlen(buf+6); + g_message("%p", flx_dns_packet_get_rptr(p)); + + if (flx_dns_packet_consume_bytes(p, &r->data.a.address, sizeof(flxIPv4Address)) < 0) + goto fail; + + g_message("%p", flx_dns_packet_get_rptr(p)); + + break; + + case FLX_DNS_TYPE_AAAA: + + g_message("aaaa"); + + if (flx_dns_packet_consume_bytes(p, &r->data.aaaa.address, sizeof(flxIPv6Address)) < 0) + goto fail; + break; - } default: + g_message("generic"); + if (rdlength > 0) { - if (!(data = flx_dns_packet_get_rptr(p)) || - flx_dns_packet_skip(p, rdlength) < 0) - return NULL; - } else - data = NULL; + r->data.generic.data = g_memdup(flx_dns_packet_get_rptr(p), rdlength); + + if (flx_dns_packet_skip(p, rdlength) < 0) + goto fail; + } break; } + g_message("%i == %u ?", (guint8*) flx_dns_packet_get_rptr(p) - (guint8*) start, rdlength); + + /* Check if we read enough data */ + if ((guint8*) flx_dns_packet_get_rptr(p) - (guint8*) start != rdlength) + goto fail; + *ret_cache_flush = !!(class & MDNS_CACHE_FLUSH); class &= ~ MDNS_CACHE_FLUSH; - return flx_record_new_full(name, class, type, data, rdlength, ttl); + r->ttl = ttl; + + return r; + +fail: + if (r) + flx_record_unref(r); + + return NULL; } flxKey* flx_dns_packet_consume_key(flxDnsPacket *p) { @@ -427,7 +555,7 @@ guint8* flx_dns_packet_append_key(flxDnsPacket *p, flxKey *k) { } guint8* flx_dns_packet_append_record(flxDnsPacket *p, flxRecord *r, gboolean cache_flush) { - guint8 *t; + guint8 *t, *l, *start; guint size; g_assert(p); @@ -438,47 +566,89 @@ guint8* flx_dns_packet_append_record(flxDnsPacket *p, flxRecord *r, gboolean cac if (!(t = flx_dns_packet_append_name(p, r->key->name)) || !flx_dns_packet_append_uint16(p, r->key->type) || !flx_dns_packet_append_uint16(p, cache_flush ? (r->key->class | MDNS_CACHE_FLUSH) : (r->key->class &~ MDNS_CACHE_FLUSH)) || - !flx_dns_packet_append_uint32(p, r->ttl)) + !flx_dns_packet_append_uint32(p, r->ttl) || + !(l = flx_dns_packet_append_uint16(p, 0))) goto fail; + start = flx_dns_packet_extend(p, 0); + switch (r->key->type) { case FLX_DNS_TYPE_PTR: - case FLX_DNS_TYPE_CNAME: { - char ptr_name[257]; + case FLX_DNS_TYPE_CNAME : - g_assert((size_t) r->size+1 <= sizeof(ptr_name)); - memcpy(ptr_name, r->data, r->size); - ptr_name[r->size] = 0; + if (!(flx_dns_packet_append_name(p, r->data.ptr.name))) + goto fail; - if (!flx_dns_packet_append_uint16(p, strlen(ptr_name)+1) || - !flx_dns_packet_append_name(p, ptr_name)) + break; + + case FLX_DNS_TYPE_SRV: + + if (!flx_dns_packet_append_uint16(p, r->data.srv.priority) || + !flx_dns_packet_append_uint16(p, r->data.srv.weight) || + !flx_dns_packet_append_uint16(p, r->data.srv.port) || + !flx_dns_packet_append_name(p, r->data.srv.name)) goto fail; break; - } - case FLX_DNS_TYPE_SRV: { - char name[257]; + case FLX_DNS_TYPE_HINFO: + if (!flx_dns_packet_append_string(p, r->data.hinfo.cpu) || + !flx_dns_packet_append_string(p, r->data.hinfo.os)) + goto fail; + + break; + + case FLX_DNS_TYPE_TXT: { + + guint8 *data; + guint size; - g_assert(r->size >= 6 && (size_t) r->size-6+1 <= sizeof(name)); - memcpy(name, r->data+6, r->size-6); - name[r->size-6] = 0; + size = flx_string_list_serialize(r->data.txt.string_list, NULL, 0); - if (!flx_dns_packet_append_uint16(p, strlen(name+6)+1+6) || - !flx_dns_packet_append_bytes(p, r->data, 6) || - !flx_dns_packet_append_name(p, name)) + g_message("appending string: %u %p", size, r->data.txt.string_list); + + if (!(data = flx_dns_packet_extend(p, size))) goto fail; + flx_string_list_serialize(r->data.txt.string_list, data, size); break; } + + case FLX_DNS_TYPE_A: + + if (!flx_dns_packet_append_bytes(p, &r->data.a.address, sizeof(r->data.a.address))) + goto fail; + + break; + + case FLX_DNS_TYPE_AAAA: + + if (!flx_dns_packet_append_bytes(p, &r->data.aaaa.address, sizeof(r->data.aaaa.address))) + goto fail; + + break; + default: - if (!flx_dns_packet_append_uint16(p, r->size) || - (r->size != 0 && !flx_dns_packet_append_bytes(p, r->data, r->size))) + + if (r->data.generic.size && + flx_dns_packet_append_bytes(p, r->data.generic.data, r->data.generic.size)) goto fail; + + break; } + + + + size = flx_dns_packet_extend(p, 0) - start; + g_assert(size <= 0xFFFF); + + g_message("appended %u", size); + + * (guint16*) l = g_htons((guint16) size); + return t; diff --git a/dns.h b/dns.h index c5d2fae..38944d3 100644 --- a/dns.h +++ b/dns.h @@ -32,6 +32,7 @@ guint8 *flx_dns_packet_append_name_compressed(flxDnsPacket *p, const gchar *name 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); +guint8* flx_dns_packet_append_string(flxDnsPacket *p, const gchar *s); gint flx_dns_packet_is_query(flxDnsPacket *p); gint flx_dns_packet_check_valid(flxDnsPacket *p); @@ -42,6 +43,7 @@ gint flx_dns_packet_consume_name(flxDnsPacket *p, gchar *ret_name, guint l); gint flx_dns_packet_consume_bytes(flxDnsPacket *p, gpointer ret_data, guint l); flxKey* flx_dns_packet_consume_key(flxDnsPacket *p); flxRecord* flx_dns_packet_consume_record(flxDnsPacket *p, gboolean *ret_cache_flush); +gint flx_dns_packet_consume_string(flxDnsPacket *p, gchar *ret_string, guint l); gconstpointer flx_dns_packet_get_rptr(flxDnsPacket *p); diff --git a/flx.h b/flx.h index 1debd89..8f8b0ba 100644 --- a/flx.h +++ b/flx.h @@ -4,7 +4,6 @@ #include #include -struct _flxServer; typedef struct _flxServer flxServer; #include "address.h" @@ -23,18 +22,14 @@ void flx_server_add( gboolean unique, flxRecord *r); -void flx_server_add_full( +void flx_server_add_ptr( flxServer *s, gint id, gint interface, guchar protocol, gboolean unique, const gchar *name, - guint16 class, - guint16 type, - gconstpointer data, - guint size, - guint32 ttl); + const gchar *dest); void flx_server_add_address( flxServer *s, @@ -52,7 +47,41 @@ void flx_server_add_text( guchar protocol, gboolean unique, const gchar *name, - const gchar *text); + ... /* text records, terminated by NULL */); + +void flx_server_add_text_va( + flxServer *s, + gint id, + gint interface, + guchar protocol, + gboolean unique, + const gchar *name, + va_list va); + +void flx_server_add_service( + flxServer *s, + gint id, + gint interface, + guchar protocol, + const gchar *type, + const gchar *name, + const gchar *domain, + const gchar *host, + guint16 port, + ... /* text records, terminated by NULL */); + +void flx_server_add_service_va( + flxServer *s, + gint id, + gint interface, + guchar protocol, + const gchar *type, + const gchar *name, + const gchar *domain, + const gchar *host, + guint16 port, + va_list va); + void flx_server_remove(flxServer *s, gint id); diff --git a/main.c b/main.c index d5278c7..0479f14 100644 --- a/main.c +++ b/main.c @@ -56,7 +56,7 @@ int main(int argc, char *argv[]) { flx = flx_server_new(NULL); - flx_server_add_text(flx, 0, 0, AF_UNSPEC, FALSE, NULL, "hallo"); + flx_server_add_text(flx, 0, 0, AF_UNSPEC, FALSE, NULL, "hallo", NULL); /* k = flx_key_new("ecstasy.local.", FLX_DNS_CLASS_IN, FLX_DNS_TYPE_ANY); */ /* s = flx_subscription_new(flx, k, 0, AF_UNSPEC, subscription, NULL); */ diff --git a/rr.c b/rr.c index 600e721..a1c5868 100644 --- a/rr.c +++ b/rr.c @@ -45,31 +45,30 @@ void flx_key_unref(flxKey *k) { } } -flxRecord *flx_record_new(flxKey *k, gconstpointer data, guint16 size, guint32 ttl) { +flxRecord *flx_record_new(flxKey *k) { flxRecord *r; g_assert(k); - g_assert(size == 0 || data); r = g_new(flxRecord, 1); r->ref = 1; r->key = flx_key_ref(k); - r->data = size > 0 ? g_memdup(data, size) : NULL; - r->size = size; - r->ttl = ttl; + + memset(&r->data, 0, sizeof(r->data)); + + r->ttl = FLX_DEFAULT_TTL; return r; } -flxRecord *flx_record_new_full(const gchar *name, guint16 class, guint16 type, gconstpointer data, guint16 size, guint32 ttl) { +flxRecord *flx_record_new_full(const gchar *name, guint16 class, guint16 type) { flxRecord *r; flxKey *k; g_assert(name); - g_assert(size == 0 || data); k = flx_key_new(name, class, type); - r = flx_record_new(k, data, size, ttl); + r = flx_record_new(k); flx_key_unref(k); return r; @@ -88,8 +87,35 @@ void flx_record_unref(flxRecord *r) { g_assert(r->ref >= 1); if ((--r->ref) <= 0) { + switch (r->key->type) { + + case FLX_DNS_TYPE_SRV: + g_free(r->data.srv.name); + break; + + case FLX_DNS_TYPE_PTR: + case FLX_DNS_TYPE_CNAME: + g_free(r->data.ptr.name); + break; + + case FLX_DNS_TYPE_HINFO: + g_free(r->data.hinfo.cpu); + g_free(r->data.hinfo.os); + break; + + case FLX_DNS_TYPE_TXT: + flx_string_list_free(r->data.txt.string_list); + break; + + case FLX_DNS_TYPE_A: + case FLX_DNS_TYPE_AAAA: + break; + + default: + g_free(r->data.generic.data); + } + flx_key_unref(r->key); - g_free(r->data); g_free(r); } } @@ -123,97 +149,56 @@ const gchar *flx_dns_type_to_string(guint16 type) { } -gchar *flx_key_to_string(flxKey *k) { +gchar *flx_key_to_string(const flxKey *k) { return g_strdup_printf("%s\t%s\t%s", k->name, flx_dns_class_to_string(k->class), flx_dns_type_to_string(k->type)); } -gchar *flx_record_to_string(flxRecord *r) { +gchar *flx_record_to_string(const flxRecord *r) { gchar *p, *s; - char t[257] = ""; + char buf[257], *t, *d = NULL; switch (r->key->type) { case FLX_DNS_TYPE_A: - inet_ntop(AF_INET, r->data, t, sizeof(t)); + inet_ntop(AF_INET, &r->data.a.address.address, t = buf, sizeof(buf)); break; case FLX_DNS_TYPE_AAAA: - inet_ntop(AF_INET6, r->data, t, sizeof(t)); + inet_ntop(AF_INET6, &r->data.aaaa.address.address, t = buf, sizeof(buf)); break; - case FLX_DNS_TYPE_PTR: { - size_t l; - - l = r->size; - if (l > sizeof(t)-1) - l = sizeof(t)-1; - - memcpy(t, r->data, l); - t[l] = 0; - break; - } - - case FLX_DNS_TYPE_TXT: { + case FLX_DNS_TYPE_PTR: + case FLX_DNS_TYPE_CNAME : - if (r->size == 0) - t[0] = 0; - else { - guchar l = ((guchar*) r->data)[0]; + t = r->data.ptr.name; + break; - if ((size_t) l+1 <= r->size) { - memcpy(t, r->data+1, ((guchar*) r->data)[0]); - t[((guchar*) r->data)[0]] = 0; - } - } + case FLX_DNS_TYPE_TXT: + t = d = flx_string_list_to_string(r->data.txt.string_list); break; - } - case FLX_DNS_TYPE_HINFO: { - gchar *s2; - gchar hi1[256], hi2[256]; - guchar len; - - if ((size_t) (len = ((guchar*) r->data)[0]) + 2 <= r->size) { - guchar len2; - memcpy(hi1, (gchar*) r->data +1, len); - hi1[len] = 0; - - if ((size_t) (len2 = ((guchar*) r->data)[len+1]) + len + 2 <= r->size) { - memcpy(hi2, (gchar*) r->data+len+2, len2); - hi2[len2] = 0; - snprintf(t, sizeof(t), "'%s' '%s'", hi1, hi2); - } - - } + case FLX_DNS_TYPE_HINFO: + snprintf(t = buf, sizeof(buf), "\"%s\" \"%s\"", r->data.hinfo.cpu, r->data.hinfo.os); break; - } - case FLX_DNS_TYPE_SRV: { - char k[257]; - size_t l; + case FLX_DNS_TYPE_SRV: + + snprintf(t = buf, sizeof(buf), "%u %u %u %s", + r->data.srv.priority, + r->data.srv.weight, + r->data.srv.port, + r->data.srv.name); - l = r->size-6; - if (l > sizeof(k)-1) - l = sizeof(k)-1; - - memcpy(k, r->data+6, l); - k[l] = 0; - - snprintf(t, sizeof(t), "%u %u %u %s", - ntohs(((guint16*) r->data)[0]), - ntohs(((guint16*) r->data)[1]), - ntohs(((guint16*) r->data)[2]), - k); break; - } } p = flx_key_to_string(r->key); - s = g_strdup_printf("%s %s ; ttl=%u", p, t, r->ttl); + s = g_strdup_printf("%s %s ; ttl=%u", p, t ? t : "", r->ttl); g_free(p); + g_free(d); return s; } @@ -255,12 +240,108 @@ guint flx_key_hash(const flxKey *k) { return g_str_hash(k->name) + k->type + k->class; } +static gboolean rdata_equal(const flxRecord *a, const flxRecord *b) { + gchar *t; + g_assert(a); + g_assert(b); + g_assert(a->key->type == b->key->type); + + t = flx_record_to_string(a); + g_message("comparing %s", t); + g_free(t); + + t = flx_record_to_string(b); + g_message("and %s", t); + g_free(t); + + + switch (a->key->type) { + case FLX_DNS_TYPE_SRV: + return + 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); + + case FLX_DNS_TYPE_PTR: + case FLX_DNS_TYPE_CNAME: + return !strcmp(a->data.ptr.name, b->data.ptr.name); + + case FLX_DNS_TYPE_HINFO: + return + !strcmp(a->data.hinfo.cpu, b->data.hinfo.cpu) && + !strcmp(a->data.hinfo.os, b->data.hinfo.os); + + case FLX_DNS_TYPE_TXT: + return flx_string_list_equal(a->data.txt.string_list, b->data.txt.string_list); + + case FLX_DNS_TYPE_A: + return memcmp(&a->data.a.address, &b->data.a.address, sizeof(flxIPv4Address)) == 0; + + case FLX_DNS_TYPE_AAAA: + return memcmp(&a->data.aaaa.address, &b->data.aaaa.address, sizeof(flxIPv6Address)) == 0; + + default: + return a->data.generic.size == b->data.generic.size && + (a->data.generic.size == 0 || memcmp(a->data.generic.data, b->data.generic.data, a->data.generic.size) == 0); + } + +} + gboolean flx_record_equal_no_ttl(const flxRecord *a, const flxRecord *b) { g_assert(a); g_assert(b); - return flx_key_equal(a->key, b->key) && -/* a->ttl == b->ttl && */ - a->size == b->size && - (a->size == 0 || memcmp(a->data, b->data, a->size) == 0); + return + flx_key_equal(a->key, b->key) && + rdata_equal(a, b); +} + + +flxRecord *flx_record_copy(flxRecord *r) { + flxRecord *copy; + + copy = g_new(flxRecord, 1); + copy->ref = 1; + copy->key = flx_key_ref(r->key); + copy->ttl = r->ttl; + + switch (r->key->type) { + case FLX_DNS_TYPE_PTR: + case FLX_DNS_TYPE_CNAME: + copy->data.ptr.name = g_strdup(r->data.ptr.name); + break; + + case FLX_DNS_TYPE_SRV: + copy->data.srv.priority = r->data.srv.priority; + copy->data.srv.weight = r->data.srv.weight; + copy->data.srv.port = r->data.srv.port; + copy->data.srv.name = g_strdup(r->data.srv.name); + break; + + case FLX_DNS_TYPE_HINFO: + copy->data.hinfo.os = g_strdup(r->data.hinfo.os); + copy->data.hinfo.cpu = g_strdup(r->data.hinfo.cpu); + break; + + case FLX_DNS_TYPE_TXT: + copy->data.txt.string_list = flx_string_list_copy(r->data.txt.string_list); + break; + + case FLX_DNS_TYPE_A: + copy->data.a.address = r->data.a.address; + break; + + case FLX_DNS_TYPE_AAAA: + copy->data.aaaa.address = r->data.aaaa.address; + break; + + default: + copy->data.generic.data = g_memdup(r->data.generic.data, r->data.generic.size); + copy->data.generic.size = r->data.generic.size; + break; + + } + + return copy; } diff --git a/rr.h b/rr.h index 65abb1d..1ba6d95 100644 --- a/rr.h +++ b/rr.h @@ -3,6 +3,9 @@ #include +#include "strlst.h" +#include "address.h" + enum { FLX_DNS_TYPE_A = 0x01, FLX_DNS_TYPE_NS = 0x02, @@ -34,9 +37,44 @@ typedef struct { guint ref; flxKey *key; - gpointer data; - guint16 size; guint32 ttl; + + union { + struct { + gpointer data; + guint16 size; + } generic; + + struct { + guint16 priority; + guint16 weight; + guint16 port; + gchar *name; + } srv; + + struct { + gchar *name; + } ptr; /* and cname */ + + struct { + gchar *cpu; + gchar *os; + } hinfo; + + struct { + flxStringList *string_list; + } txt; + + struct { + flxIPv4Address address; + } a; + + struct { + flxIPv6Address address; + } aaaa; + + } data; + } flxRecord; flxKey *flx_key_new(const gchar *name, guint16 class, guint16 type); @@ -50,17 +88,19 @@ gboolean flx_key_is_pattern(const flxKey *k); guint flx_key_hash(const flxKey *k); -flxRecord *flx_record_new(flxKey *k, gconstpointer data, guint16 size, guint32 ttl); -flxRecord *flx_record_new_full(const gchar *name, guint16 class, guint16 type, gconstpointer data, guint16 size, guint32 ttl); +flxRecord *flx_record_new(flxKey *k); +flxRecord *flx_record_new_full(const gchar *name, guint16 class, guint16 type); flxRecord *flx_record_ref(flxRecord *r); void flx_record_unref(flxRecord *r); const gchar *flx_dns_class_to_string(guint16 class); const gchar *flx_dns_type_to_string(guint16 type); -gchar *flx_key_to_string(flxKey *k); /* g_free() the result! */ -gchar *flx_record_to_string(flxRecord *r); /* g_free() the result! */ +gchar *flx_key_to_string(const flxKey *k); /* g_free() the result! */ +gchar *flx_record_to_string(const flxRecord *r); /* g_free() the result! */ gboolean flx_record_equal_no_ttl(const flxRecord *a, const flxRecord *b); +flxRecord *flx_record_copy(flxRecord *r); + #endif diff --git a/server.c b/server.c index 04c7d10..fcf4248 100644 --- a/server.c +++ b/server.c @@ -92,19 +92,20 @@ static void handle_response(flxServer *s, flxDnsPacket *p, flxInterface *i, cons gchar *txt; if (!(record = flx_dns_packet_consume_record(p, &cache_flush))) { - g_warning("Packet too short"); + g_warning("Packet too short (3)"); return; } - if (record->key->type != FLX_DNS_TYPE_ANY) { - g_message("Handling response: %s", txt = flx_record_to_string(record)); - g_free(txt); - - flx_cache_update(i->cache, record, cache_flush, a); - - flx_packet_scheduler_incoming_response(i->scheduler, record); - flx_record_unref(record); - } + if (record->key->type == FLX_DNS_TYPE_ANY) + continue; + + g_message("Handling response: %s", txt = flx_record_to_string(record)); + g_free(txt); + + flx_cache_update(i->cache, record, cache_flush, a); + + flx_packet_scheduler_incoming_response(i->scheduler, record); + flx_record_unref(record); } } @@ -232,20 +233,17 @@ static void add_default_entries(flxServer *s) { struct utsname utsname; gchar *hinfo; flxAddress a; + flxRecord *r; g_assert(s); /* Fill in HINFO rr */ + r = flx_record_new_full(s->hostname, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_HINFO); uname(&utsname); - hinfo = g_strdup_printf("%c%s%c%s%n", - strlen(utsname.machine), g_strup(utsname.machine), - strlen(utsname.sysname), g_strup(utsname.sysname), - &length); - - flx_server_add_full(s, 0, 0, AF_UNSPEC, TRUE, - s->hostname, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_HINFO, hinfo, length, FLX_DEFAULT_TTL); - - g_free(hinfo); + r->data.hinfo.cpu = g_strdup(g_strup(utsname.machine)); + r->data.hinfo.os = g_strdup(g_strup(utsname.sysname)); + flx_server_add(s, 0, 0, AF_UNSPEC, TRUE, r); + flx_record_unref(r); /* Add localhost entries */ flx_address_parse("127.0.0.1", AF_INET, &a); @@ -402,30 +400,6 @@ void flx_server_add( flx_announce_entry(s, e); } - -void flx_server_add_full( - flxServer *s, - gint id, - gint interface, - guchar protocol, - gboolean unique, - const gchar *name, - guint16 class, - guint16 type, - gconstpointer data, - guint size, - guint32 ttl) { - - flxRecord *r; - g_assert(s); - g_assert(data); - g_assert(size); - - r = flx_record_new_full(name ? name : s->hostname, class, type, data, size, ttl); - flx_server_add(s, id, interface, protocol, unique, r); - flx_record_unref(r); -} - const flxRecord *flx_server_iterate(flxServer *s, gint id, void **state) { flxServerEntry **e = (flxServerEntry**) state; g_assert(s); @@ -504,6 +478,26 @@ void flx_server_dump(flxServer *s, FILE *f) { flx_dump_caches(s->monitor, f); } +void flx_server_add_ptr( + flxServer *s, + gint id, + gint interface, + guchar protocol, + gboolean unique, + const gchar *name, + const gchar *dest) { + + flxRecord *r; + + g_assert(dest); + + r = flx_record_new_full(name ? name : s->hostname, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_PTR); + r->data.ptr.name = flx_normalize_name(dest); + flx_server_add(s, id, interface, protocol, unique, r); + flx_record_unref(r); + +} + void flx_server_add_address( flxServer *s, gint id, @@ -513,41 +507,68 @@ void flx_server_add_address( const gchar *name, flxAddress *a) { - gchar *n; + gchar *n = NULL; g_assert(s); g_assert(a); - n = name ? flx_normalize_name(name) : s->hostname; + name = name ? (n = flx_normalize_name(name)) : s->hostname; if (a->family == AF_INET) { - gchar *r; - - flx_server_add_full(s, id, interface, protocol, unique, n, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_A, &a->data.ipv4, sizeof(a->data.ipv4), FLX_DEFAULT_TTL); + gchar *reverse; + flxRecord *r; - r = flx_reverse_lookup_name_ipv4(&a->data.ipv4); - g_assert(r); - flx_server_add_full(s, id, interface, protocol, unique, r, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_PTR, n, strlen(n)+1, FLX_DEFAULT_TTL); - g_free(r); + r = flx_record_new_full(name, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_A); + r->data.a.address = a->data.ipv4; + flx_server_add(s, id, interface, protocol, unique, r); + flx_record_unref(r); + + reverse = flx_reverse_lookup_name_ipv4(&a->data.ipv4); + g_assert(reverse); + flx_server_add_ptr(s, id, interface, protocol, unique, reverse, name); + g_free(reverse); } else { - gchar *r; + gchar *reverse; + flxRecord *r; - flx_server_add_full(s, id, interface, protocol, unique, n, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_AAAA, &a->data.ipv6, sizeof(a->data.ipv6), FLX_DEFAULT_TTL); - - r = flx_reverse_lookup_name_ipv6_arpa(&a->data.ipv6); - g_assert(r); - flx_server_add_full(s, id, interface, protocol, unique, r, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_PTR, n, strlen(n)+1, FLX_DEFAULT_TTL); - g_free(r); + r = flx_record_new_full(name, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_AAAA); + r->data.aaaa.address = a->data.ipv6; + flx_server_add(s, id, interface, protocol, unique, r); + flx_record_unref(r); + + reverse = flx_reverse_lookup_name_ipv6_arpa(&a->data.ipv6); + g_assert(reverse); + flx_server_add_ptr(s, id, interface, protocol, unique, reverse, name); + g_free(reverse); - r = flx_reverse_lookup_name_ipv6_int(&a->data.ipv6); - g_assert(r); - flx_server_add_full(s, id, interface, protocol, unique, r, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_PTR, n, strlen(n)+1, FLX_DEFAULT_TTL); - g_free(r); + reverse = flx_reverse_lookup_name_ipv6_int(&a->data.ipv6); + g_assert(reverse); + flx_server_add_ptr(s, id, interface, protocol, unique, reverse, name); + g_free(reverse); } g_free(n); } +void flx_server_add_text_va( + flxServer *s, + gint id, + gint interface, + guchar protocol, + gboolean unique, + const gchar *name, + va_list va) { + + flxRecord *r; + + g_assert(s); + + r = flx_record_new_full(name ? name : s->hostname, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_TXT); + r->data.txt.string_list = flx_string_list_new_va(va); + flx_server_add(s, id, interface, protocol, unique, r); + flx_record_unref(r); +} + void flx_server_add_text( flxServer *s, gint id, @@ -555,22 +576,110 @@ void flx_server_add_text( guchar protocol, gboolean unique, const gchar *name, - const gchar *text) { + ...) { + + va_list va; - gchar buf[256]; - guint l; + g_assert(s); + + va_start(va, name); + flx_server_add_text_va(s, id, interface, protocol, unique, name, va); + va_end(va); +} + +static void escape_service_name(gchar *d, guint size, const gchar *s) { + g_assert(d); + g_assert(size); + g_assert(s); + + while (*s && size >= 2) { + if (*s == '.' || *s == '\\') { + if (size < 3) + break; + + *(d++) = '\\'; + size--; + } + + *(d++) = *(s++); + size--; + } + + g_assert(size > 0); + *(d++) = 0; +} + + +void flx_server_add_service_va( + flxServer *s, + gint id, + gint interface, + guchar protocol, + const gchar *type, + const gchar *name, + const gchar *domain, + const gchar *host, + guint16 port, + va_list va) { + + gchar ptr_name[256], svc_name[256], ename[64], enum_ptr[256]; + flxRecord *r; g_assert(s); - g_assert(text); + g_assert(type); + g_assert(name); - if ((l = strlen(text)) > 255) - buf[0] = 255; - else - buf[0] = (gchar) l; + escape_service_name(ename, sizeof(ename), name); + + if (domain) { + while (domain[0] == '.') + domain++; + } else + domain = "local"; - memcpy(buf+1, text, l); + if (!host) + host = s->hostname; + + snprintf(ptr_name, sizeof(ptr_name), "%s.%s", type, domain); + snprintf(svc_name, sizeof(svc_name), "%s.%s.%s", ename, type, domain); + + flx_server_add_ptr(s, id, interface, protocol, FALSE, ptr_name, svc_name); + + r = flx_record_new_full(svc_name, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_SRV); + r->data.srv.priority = 0; + r->data.srv.weight = 0; + r->data.srv.port = port; + r->data.srv.name = flx_normalize_name(host); + flx_server_add(s, id, interface, protocol, TRUE, r); + flx_record_unref(r); + + flx_server_add_text_va(s, id, interface, protocol, FALSE, svc_name, va); + + snprintf(enum_ptr, sizeof(enum_ptr), "_services._dns-sd._udp.%s", domain); + flx_server_add_ptr(s, id, interface, protocol, FALSE, enum_ptr, ptr_name); +} + +void flx_server_add_service( + flxServer *s, + gint id, + gint interface, + guchar protocol, + const gchar *type, + const gchar *name, + const gchar *domain, + const gchar *host, + guint16 port, + ... ){ + + va_list va; + + g_assert(s); + g_assert(type); + g_assert(name); - flx_server_add_full(s, id, interface, protocol, unique, name, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_TXT, buf, l+1, FLX_DEFAULT_TTL); + va_start(va, port); + flx_server_add_service_va(s, id, interface, protocol, type, name, domain, host, port, va); + va_end(va); } static void post_query_callback(flxInterfaceMonitor *m, flxInterface *i, gpointer userdata) { diff --git a/strlst-test.c b/strlst-test.c new file mode 100644 index 0000000..c4cef31 --- /dev/null +++ b/strlst-test.c @@ -0,0 +1,46 @@ +#include +#include + +#include "strlst.h" + +int main(int argc, char *argv[]) { + gchar *t; + guint8 data[1024]; + flxStringList *a = NULL, *b; + guint size, n; + + a = flx_string_list_add(a, "foo"); + a = flx_string_list_add(a, "bar"); + a = flx_string_list_add(a, "baz"); + + t = flx_string_list_to_string(a); + printf("--%s--\n", t); + g_free(t); + + size = flx_string_list_serialize(a, data, sizeof(data)); + + printf("%u\n", size); + + for (t = (gchar*) data, n = 0; n < size; n++, t++) { + if (*t <= 32) + printf("(%u)", *t); + else + printf("%c", *t); + } + + printf("\n"); + + b = flx_string_list_parse(data, size); + + g_assert(flx_string_list_equal(a, b)); + + t = flx_string_list_to_string(b); + printf("--%s--\n", t); + g_free(t); + + + flx_string_list_free(a); + flx_string_list_free(b); + + return 0; +} diff --git a/strlst.c b/strlst.c new file mode 100644 index 0000000..8993f3a --- /dev/null +++ b/strlst.c @@ -0,0 +1,215 @@ +#include +#include + +#include "strlst.h" + +static flxStringList *string_list_add_internal(flxStringList *l, const gchar *text, guint size) { + flxStringList *n; + + g_assert(text); + + n = g_malloc(sizeof(flxStringList) + size); + n->next = l; + strncpy(n->text, text, size); + n->text[size] = 0; + + return n; +} + +flxStringList *flx_string_list_add(flxStringList *l, const gchar *text) { + g_assert(text); + + return string_list_add_internal(l, text, strlen(text)); +} + +flxStringList *flx_string_list_parse(gconstpointer data, guint size) { + flxStringList *r = NULL; + const guint8 *c; + g_assert(data); + + c = data; + for (;;) { + guint k; + + if (size < 1) + break; + + k = *(c++); + r = string_list_add_internal(r, (const gchar*) c, k); + c += k; + + size -= 1 + k; + } + + return r; +} + +void flx_string_list_free(flxStringList *l) { + flxStringList *n; + + while (l) { + n = l->next; + g_free(l); + l = n; + } +} + + +static flxStringList* string_list_reverse(flxStringList *l) { + flxStringList *r = NULL, *n; + + while (l) { + n = l->next; + l->next = r; + r = l; + l = n; + } + + return r; +} + +gchar* flx_string_list_to_string(flxStringList *l) { + flxStringList *n; + guint s = 0; + gchar *t, *e; + + l = string_list_reverse(l); + + for (n = l; n; n = n->next) { + if (n != l) + s ++; + + s += strlen(n->text)+2; + } + + t = e = g_new(gchar, s+1); + + for (n = l; n; n = n->next) { + if (n != l) + *(e++) = ' '; + + *(e++) = '"'; + strcpy(e, n->text); + e += strlen(n->text); + *(e++) = '"'; + } + + l = string_list_reverse(l); + + *e = 0; + + return t; +} + +guint flx_string_list_serialize(flxStringList *l, gpointer data, guint size) { + guint used = 0; + + if (data) { + guint8 *c; + flxStringList *n; + + g_assert(data); + + l = string_list_reverse(l); + c = data; + + for (n = l; n; n = n->next) { + guint k; + if (size < 1) + break; + + k = strlen(n->text); + if (k > 255) + k = 255; + + if (k > size-1) + k = size-1; + + *(c++) = k; + memcpy(c, n->text, k); + c += k; + + used += 1+ k; + } + + l = string_list_reverse(l); + } else { + flxStringList *n; + + for (n = l; n; n = n->next) { + guint k; + + k = strlen(n->text); + if (k > 255) + k = 255; + + used += 1+k; + } + } + + return used; +} + +gboolean flx_string_list_equal(flxStringList *a, flxStringList *b) { + + for (;;) { + if (!a && !b) + return TRUE; + + if (!a || !b) + return FALSE; + + if (strcmp(a->text, b->text) != 0) + return FALSE; + + a = a->next; + b = b->next; + } +} + +flxStringList *flx_string_list_add_many(flxStringList *r, ...) { + va_list va; + + va_start(va, r); + r = flx_string_list_add_many_va(r, va); + va_end(va); + + return r; +} + +flxStringList *flx_string_list_add_many_va(flxStringList *r, va_list va) { + const gchar *txt; + + while ((txt = va_arg(va, const gchar*))) + r = flx_string_list_add(r, txt); + + return r; +} + +flxStringList *flx_string_list_new(const gchar *txt, ...) { + va_list va; + flxStringList *r = NULL; + + if (txt) { + r = flx_string_list_add(r, txt); + + va_start(va, txt); + r = flx_string_list_add_many_va(r, va); + va_end(va); + } + + return r; +} + +flxStringList *flx_string_list_new_va(va_list va) { + return flx_string_list_add_many_va(NULL, va); +} + +flxStringList *flx_string_list_copy(flxStringList *l) { + flxStringList *r; + + for (; l; l = l->next) + r = flx_string_list_add(l, l->text); + + return string_list_reverse(r); +} diff --git a/strlst.h b/strlst.h new file mode 100644 index 0000000..94fb563 --- /dev/null +++ b/strlst.h @@ -0,0 +1,32 @@ +#ifndef footxtlisthfoo +#define footxtlisthfoo + +#include + +typedef struct _flxStringList flxStringList; + +struct _flxStringList { + flxStringList *next; + gchar text[1]; +}; + +flxStringList *flx_string_list_new(const gchar *txt, ...); +flxStringList *flx_string_list_new_va(va_list va); + +void flx_string_list_free(flxStringList *l); + +flxStringList *flx_string_list_add(flxStringList *l, const gchar *text); +flxStringList *flx_string_list_add_many(flxStringList *r, ...); +flxStringList *flx_string_list_add_many_va(flxStringList *r, va_list va); + +gchar* flx_string_list_to_string(flxStringList *l); + +guint flx_string_list_serialize(flxStringList *l, gpointer data, guint size); +flxStringList *flx_string_list_parse(gconstpointer data, guint size); + +gboolean flx_string_list_equal(flxStringList *a, flxStringList *b); + +flxStringList *flx_string_list_copy(flxStringList *l); + +#endif + diff --git a/todo b/todo index 786a0ec..8f31542 100644 --- a/todo +++ b/todo @@ -12,8 +12,6 @@ todo: * add SRV and TXT records referenced from PTR records automatically to packet * add A and AAAA records referenced from SRV records automatically to packet -* make flx_server_add_text() and flx_server_add_service() variadic functions - * name compression * respect escaping in name serialization @@ -24,3 +22,5 @@ done: * FLX_DNS_TYPE_ANY support * Known-Answer suppression client part * Known-Answer suppression server part +* make flx_server_add_text() and flx_server_add_service() variadic functions + -- 2.39.5