X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=rr.c;h=db816588e2ccf878825cdd8d91908f6a76c25627;hb=96c58e8ba51d67d1d90660ba8ff4f597c03688fe;hp=4108c54cf1be6cba627b38a772dcd1ca89eeb0fe;hpb=8e7f83aa5b6d910e80c56b31f4eb79b02e7ca67b;p=catta diff --git a/rr.c b/rr.c index 4108c54..db81658 100644 --- a/rr.c +++ b/rr.c @@ -6,6 +6,7 @@ #include "util.h" #include "rr.h" +#include "dns.h" flxKey *flx_key_new(const gchar *name, guint16 class, guint16 type) { flxKey *k; @@ -45,28 +46,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(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); 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; @@ -85,13 +88,43 @@ 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); } } const gchar *flx_dns_class_to_string(guint16 class) { + if (class & FLX_DNS_CACHE_FLUSH) + return "FLUSH"; + if (class == FLX_DNS_CLASS_IN) return "IN"; @@ -114,103 +147,64 @@ const gchar *flx_dns_type_to_string(guint16 type) { return "TXT"; case FLX_DNS_TYPE_SRV: return "SRV"; + case FLX_DNS_TYPE_ANY: + return "ANY"; default: return NULL; } } -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 = NULL, *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; } @@ -221,21 +215,330 @@ gboolean flx_key_equal(const flxKey *a, const flxKey *b) { /* g_message("equal: %p %p", a, b); */ - return strcmp(a->name, b->name) == 0 && a->type == b->type && a->class == b->class; + return flx_domain_equal(a->name, b->name) && + a->type == b->type && + a->class == b->class; } +gboolean flx_key_pattern_match(const flxKey *pattern, const flxKey *k) { + g_assert(pattern); + g_assert(k); + +/* g_message("equal: %p %p", a, b); */ + + g_assert(!flx_key_is_pattern(k)); + + return flx_domain_equal(pattern->name, k->name) && + (pattern->type == k->type || pattern->type == FLX_DNS_TYPE_ANY) && + pattern->class == k->class; +} + +gboolean flx_key_is_pattern(const flxKey *k) { + g_assert(k); + + return k->type == FLX_DNS_TYPE_ANY; +} + + 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) { + 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 && + flx_domain_equal(a->data.srv.name, b->data.srv.name); + + case FLX_DNS_TYPE_PTR: + case FLX_DNS_TYPE_CNAME: + return flx_domain_equal(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; +} + + +guint flx_key_get_estimate_size(flxKey *k) { + g_assert(k); + + return strlen(k->name)+1+4; +} + +guint flx_record_get_estimate_size(flxRecord *r) { + guint n; + g_assert(r); + + n = flx_key_get_estimate_size(r->key) + 4 + 2; + + switch (r->key->type) { + case FLX_DNS_TYPE_PTR: + case FLX_DNS_TYPE_CNAME: + n += strlen(r->data.ptr.name) + 1; + break; + + case FLX_DNS_TYPE_SRV: + n += 6 + strlen(r->data.srv.name) + 1; + break; + + case FLX_DNS_TYPE_HINFO: + n += strlen(r->data.hinfo.os) + 1 + strlen(r->data.hinfo.cpu) + 1; + break; + + case FLX_DNS_TYPE_TXT: + n += flx_string_list_serialize(r->data.txt.string_list, NULL, 0); + break; + + case FLX_DNS_TYPE_A: + n += sizeof(flxIPv4Address); + break; + + case FLX_DNS_TYPE_AAAA: + n += sizeof(flxIPv6Address); + break; + + default: + n += r->data.generic.size; + } + + return n; +} + +static gint lexicographical_memcmp(gconstpointer a, size_t al, gconstpointer b, size_t bl) { + size_t c; + gint ret; + + g_assert(a); + g_assert(b); + + c = al < bl ? al : bl; + if ((ret = memcmp(a, b, c)) != 0) + return ret; + + if (al == bl) + return 0; + else + return al == c ? 1 : -1; +} + +static gint uint16_cmp(guint16 a, guint16 b) { + return a == b ? 0 : (a < b ? a : b); +} + +static gint lexicographical_domain_cmp(const gchar *a, const gchar *b) { + g_assert(a); + g_assert(b); + + + for (;;) { + gchar t1[64]; + gchar t2[64]; + size_t al, bl; + gint r; + + if (!a && !b) + return 0; + + if (a && !b) + return 1; + + if (b && !a) + return -1; + + flx_unescape_label(t1, sizeof(t1), &a); + flx_unescape_label(t2, sizeof(t2), &b); + + al = strlen(t1); + bl = strlen(t2); + + if (al != bl) + return al < bl ? -1 : 1; + + if ((r = strcmp(t1, t2)) != 0) + return r; + } +} + +gint flx_record_lexicographical_compare(flxRecord *a, flxRecord *b) { + g_assert(a); + g_assert(b); + +/* gchar *t; */ + +/* g_message("comparing [%s]", t = flx_record_to_string(a)); */ +/* g_free(t); */ + +/* g_message("and [%s]", t = flx_record_to_string(b)); */ +/* g_free(t); */ + + if (a->key->class < b->key->class) + return -1; + else if (a->key->class > b->key->class) + return 1; + + if (a->key->type < b->key->type) + return -1; + else if (a->key->type > b->key->type) + return 1; + + switch (a->key->type) { + + case FLX_DNS_TYPE_PTR: + case FLX_DNS_TYPE_CNAME: + return lexicographical_domain_cmp(a->data.ptr.name, b->data.ptr.name); + + case FLX_DNS_TYPE_SRV: { + gint r; + if ((r = uint16_cmp(a->data.srv.priority, b->data.srv.priority)) == 0 && + (r = uint16_cmp(a->data.srv.weight, b->data.srv.weight)) == 0 && + (r = uint16_cmp(a->data.srv.port, b->data.srv.port)) == 0) + r = lexicographical_domain_cmp(a->data.srv.name, b->data.srv.name); + + return r; + } + + case FLX_DNS_TYPE_HINFO: { + size_t al = strlen(a->data.hinfo.cpu), bl = strlen(b->data.hinfo.cpu); + gint r; + + if (al != bl) + return al < bl ? -1 : 1; + + if ((r = strcmp(a->data.hinfo.cpu, b->data.hinfo.cpu)) != 0) + return r; + + al = strlen(a->data.hinfo.os), bl = strlen(b->data.hinfo.os); + + if (al != bl) + return al < bl ? -1 : 1; + + if ((r = strcmp(a->data.hinfo.os, b->data.hinfo.os)) != 0) + return r; + + return 0; + + } + + case FLX_DNS_TYPE_TXT: { + + guint8 *ma, *mb; + guint asize, bsize; + gint r; + + ma = g_new(guint8, asize = flx_string_list_serialize(a->data.txt.string_list, NULL, 0)); + mb = g_new(guint8, bsize = flx_string_list_serialize(b->data.txt.string_list, NULL, 0)); + flx_string_list_serialize(a->data.txt.string_list, ma, asize); + flx_string_list_serialize(a->data.txt.string_list, mb, bsize); + + r = lexicographical_memcmp(ma, asize, mb, bsize); + g_free(ma); + g_free(mb); + + return r; + } + + case FLX_DNS_TYPE_A: + return memcmp(&a->data.a.address, &b->data.a.address, sizeof(flxIPv4Address)); + + case FLX_DNS_TYPE_AAAA: + return memcmp(&a->data.aaaa.address, &b->data.aaaa.address, sizeof(flxIPv6Address)); + + default: + return lexicographical_memcmp(a->data.generic.data, a->data.generic.size, + b->data.generic.data, b->data.generic.size); + } + }