X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=dns.c;h=d518a305690dac40adf4eb14ae4b0ce872e1e179;hb=ba8547ee3f34d8fe7bedb559530b2c0374f2089c;hp=9126100ac096b3a8944193651d89950923ab1765;hpb=fc174c871b4f85e558766c1ca55661fa7b1b4c9a;p=catta diff --git a/dns.c b/dns.c index 9126100..d518a30 100644 --- a/dns.c +++ b/dns.c @@ -5,6 +5,7 @@ #include #include "dns.h" +#include "util.h" flxDnsPacket* flx_dns_packet_new(guint max_size) { flxDnsPacket *p; @@ -17,6 +18,7 @@ flxDnsPacket* flx_dns_packet_new(guint max_size) { p = g_malloc(sizeof(flxDnsPacket) + max_size); p->size = p->rindex = FLX_DNS_PACKET_HEADER_SIZE; p->max_size = max_size; + p->name_table = NULL; memset(FLX_DNS_PACKET_DATA(p), 0, p->size); return p; @@ -26,7 +28,7 @@ flxDnsPacket* flx_dns_packet_new_query(guint max_size) { flxDnsPacket *p; p = flx_dns_packet_new(max_size); - flx_dns_packet_set_field(p, DNS_FIELD_FLAGS, DNS_FLAGS(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)); + flx_dns_packet_set_field(p, FLX_DNS_FIELD_FLAGS, FLX_DNS_FLAGS(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)); return p; } @@ -34,12 +36,16 @@ flxDnsPacket* flx_dns_packet_new_response(guint max_size) { flxDnsPacket *p; p = flx_dns_packet_new(max_size); - flx_dns_packet_set_field(p, DNS_FIELD_FLAGS, DNS_FLAGS(1, 0, 0, 0, 0, 0, 0, 0, 0, 0)); + flx_dns_packet_set_field(p, FLX_DNS_FIELD_FLAGS, FLX_DNS_FLAGS(1, 0, 0, 0, 0, 0, 0, 0, 0, 0)); return p; } void flx_dns_packet_free(flxDnsPacket *p) { g_assert(p); + + if (p->name_table) + g_hash_table_destroy(p->name_table); + g_free(p); } @@ -57,47 +63,104 @@ 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; + guint8 *d, *saved_ptr = NULL; guint saved_size; g_assert(p); g_assert(name); saved_size = p->size; + saved_ptr = flx_dns_packet_extend(p, 0); + + while (*name) { + guint n; + guint8* prev; + const gchar *pname; + char label[64]; - for (;;) { - guint n = strcspn(name, "."); - if (!n || n > 63) - goto fail; - - if (!(d = flx_dns_packet_extend(p, n+1))) - goto fail; + /* Check whether we can compress this name. */ + + if (p->name_table && (prev = g_hash_table_lookup(p->name_table, name))) { + guint index; - if (!f) - f = d; - d[0] = n; - memcpy(d+1, name, n); + g_assert(prev >= FLX_DNS_PACKET_DATA(p)); + index = (guint) (prev - FLX_DNS_PACKET_DATA(p)); - name += n; + g_assert(index < p->size); - /* no trailing dot */ - if (!*name) - break; + if (index < 0x4000) { + guint16 *t; + if (!(t = (guint16*) flx_dns_packet_extend(p, sizeof(guint16)))) + return NULL; - name ++; + *t = g_htons((0xC000 | index)); + return saved_ptr; + } + } - /* trailing dot */ - if (!*name) - break; + pname = name; + + if (!(unescape_label(label, sizeof(label), &name))) + goto fail; + + 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(pname), d); } if (!(d = flx_dns_packet_extend(p, 1))) goto fail; - d[0] = 0; + *d = 0; - return f; + return saved_ptr; fail: p->size = saved_size; @@ -174,25 +237,6 @@ guint8 *flx_dns_packet_extend(flxDnsPacket *p, guint l) { return d; } -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; -} - gint flx_dns_packet_check_valid(flxDnsPacket *p) { guint16 flags; g_assert(p); @@ -200,9 +244,9 @@ gint flx_dns_packet_check_valid(flxDnsPacket *p) { if (p->size < 12) return -1; - flags = flx_dns_packet_get_field(p, DNS_FIELD_FLAGS); + flags = flx_dns_packet_get_field(p, FLX_DNS_FIELD_FLAGS); - if (flags & DNS_FLAG_OPCODE || flags & DNS_FLAG_RCODE) + if (flags & FLX_DNS_FLAG_OPCODE || flags & FLX_DNS_FLAG_RCODE) return -1; return 0; @@ -211,7 +255,43 @@ gint flx_dns_packet_check_valid(flxDnsPacket *p) { gint flx_dns_packet_is_query(flxDnsPacket *p) { g_assert(p); - return !(flx_dns_packet_get_field(p, DNS_FIELD_FLAGS) & DNS_FLAG_QR); + 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) { @@ -257,10 +337,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; @@ -501,8 +581,8 @@ flxRecord* flx_dns_packet_consume_record(flxDnsPacket *p, gboolean *ret_cache_fl if ((guint8*) flx_dns_packet_get_rptr(p) - (guint8*) start != rdlength) goto fail; - *ret_cache_flush = !!(class & MDNS_CACHE_FLUSH); - class &= ~ MDNS_CACHE_FLUSH; + *ret_cache_flush = !!(class & FLX_DNS_CACHE_FLUSH); + class &= ~ FLX_DNS_CACHE_FLUSH; r->ttl = ttl; @@ -526,7 +606,7 @@ flxKey* flx_dns_packet_consume_key(flxDnsPacket *p) { flx_dns_packet_consume_uint16(p, &class) < 0) return NULL; - class &= ~ MDNS_CACHE_FLUSH; + class &= ~ FLX_DNS_CACHE_FLUSH; return flx_key_new(name, class, type); } @@ -561,7 +641,7 @@ 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_uint16(p, cache_flush ? (r->key->class | FLX_DNS_CACHE_FLUSH) : (r->key->class &~ FLX_DNS_CACHE_FLUSH)) || !flx_dns_packet_append_uint32(p, r->ttl) || !(l = flx_dns_packet_append_uint16(p, 0))) goto fail; @@ -658,3 +738,11 @@ gboolean flx_dns_packet_is_empty(flxDnsPacket *p) { return p->size <= FLX_DNS_PACKET_HEADER_SIZE; } + +guint flx_dns_packet_space(flxDnsPacket *p) { + g_assert(p); + + g_assert(p->size <= p->max_size); + + return p->max_size - p->size; +}