summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile10
-rw-r--r--announce.c7
-rw-r--r--dns.c256
-rw-r--r--dns.h2
-rw-r--r--flx.h45
-rw-r--r--main.c2
-rw-r--r--rr.c233
-rw-r--r--rr.h52
-rw-r--r--server.c255
-rw-r--r--strlst-test.c46
-rw-r--r--strlst.c215
-rw-r--r--strlst.h32
-rw-r--r--todo4
13 files changed, 946 insertions, 213 deletions
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 <netinet/in.h>
+
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
@@ -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 <stdio.h>
#include <glib.h>
-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] = "<unparsable>";
+ 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 : "<unparsable>", 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 <glib.h>
+#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 <glib.h>
+#include <stdio.h>
+
+#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 <string.h>
+#include <stdarg.h>
+
+#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 <glib.h>
+
+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
+