1 #include <netinet/in.h>
9 flxDnsPacket* flx_dns_packet_new(guint max_size) {
13 max_size = FLX_DNS_PACKET_MAX_SIZE;
14 else if (max_size < FLX_DNS_PACKET_HEADER_SIZE)
15 max_size = FLX_DNS_PACKET_HEADER_SIZE;
17 p = g_malloc(sizeof(flxDnsPacket) + max_size);
18 p->size = p->rindex = FLX_DNS_PACKET_HEADER_SIZE;
19 p->max_size = max_size;
21 memset(FLX_DNS_PACKET_DATA(p), 0, p->size);
25 flxDnsPacket* flx_dns_packet_new_query(guint max_size) {
28 p = flx_dns_packet_new(max_size);
29 flx_dns_packet_set_field(p, DNS_FIELD_FLAGS, DNS_FLAGS(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
33 flxDnsPacket* flx_dns_packet_new_response(guint max_size) {
36 p = flx_dns_packet_new(max_size);
37 flx_dns_packet_set_field(p, DNS_FIELD_FLAGS, DNS_FLAGS(1, 0, 0, 0, 0, 0, 0, 0, 0, 0));
41 void flx_dns_packet_free(flxDnsPacket *p) {
46 void flx_dns_packet_set_field(flxDnsPacket *p, guint index, guint16 v) {
48 g_assert(index < FLX_DNS_PACKET_HEADER_SIZE);
50 ((guint16*) FLX_DNS_PACKET_DATA(p))[index] = g_htons(v);
53 guint16 flx_dns_packet_get_field(flxDnsPacket *p, guint index) {
55 g_assert(index < FLX_DNS_PACKET_HEADER_SIZE);
57 return g_ntohs(((guint16*) FLX_DNS_PACKET_DATA(p))[index]);
60 guint8* flx_dns_packet_append_name(flxDnsPacket *p, const gchar *name) {
70 guint n = strcspn(name, ".");
74 if (!(d = flx_dns_packet_extend(p, n+1)))
95 if (!(d = flx_dns_packet_extend(p, 1)))
103 p->size = saved_size;
107 guint8* flx_dns_packet_append_uint16(flxDnsPacket *p, guint16 v) {
111 if (!(d = flx_dns_packet_extend(p, sizeof(guint16))))
114 *((guint16*) d) = g_htons(v);
118 guint8 *flx_dns_packet_append_uint32(flxDnsPacket *p, guint32 v) {
122 if (!(d = flx_dns_packet_extend(p, sizeof(guint32))))
125 *((guint32*) d) = g_htonl(v);
130 guint8 *flx_dns_packet_append_bytes(flxDnsPacket *p, gconstpointer b, guint l) {
137 if (!(d = flx_dns_packet_extend(p, l)))
144 guint8* flx_dns_packet_append_string(flxDnsPacket *p, const gchar *s) {
151 if ((k = strlen(s)) >= 255)
154 if (!(d = flx_dns_packet_extend(p, k+1)))
163 guint8 *flx_dns_packet_extend(flxDnsPacket *p, guint l) {
168 if (p->size+l > p->max_size)
171 d = FLX_DNS_PACKET_DATA(p) + p->size;
177 guint8 *flx_dns_packet_append_name_compressed(flxDnsPacket *p, const gchar *name, guint8 *prev) {
183 return flx_dns_packet_append_name(p, name);
185 k = prev - FLX_DNS_PACKET_DATA(p);
186 if (k < 0 || k >= 0x4000 || (guint) k >= p->size)
187 return flx_dns_packet_append_name(p, name);
189 if (!(d = (guint16*) flx_dns_packet_extend(p, sizeof(guint16))))
192 *d = g_htons((0xC000 | k));
196 gint flx_dns_packet_check_valid(flxDnsPacket *p) {
203 flags = flx_dns_packet_get_field(p, DNS_FIELD_FLAGS);
205 if (flags & DNS_FLAG_OPCODE || flags & DNS_FLAG_RCODE)
211 gint flx_dns_packet_is_query(flxDnsPacket *p) {
214 return !(flx_dns_packet_get_field(p, DNS_FIELD_FLAGS) & DNS_FLAG_QR);
217 static gint consume_labels(flxDnsPacket *p, guint index, gchar *ret_name, guint l) {
221 g_assert(p && ret_name && l);
226 if (index+1 > p->size)
229 n = FLX_DNS_PACKET_DATA(p)[index];
242 } else if (n <= 63) {
243 /* Uncompressed label */
248 if (index + n > p->size)
251 if ((guint) n + 1 > l)
260 memcpy(ret_name, FLX_DNS_PACKET_DATA(p) + index, n);
267 } else if ((n & 0xC0) == 0xC0) {
268 /* Compressed label */
270 if (index+2 > p->size)
273 index = ((guint) (FLX_DNS_PACKET_DATA(p)[index] & ~0xC0)) << 8 | FLX_DNS_PACKET_DATA(p)[index+1];
284 gint flx_dns_packet_consume_name(flxDnsPacket *p, gchar *ret_name, guint l) {
287 if ((r = consume_labels(p, p->rindex, ret_name, l)) < 0)
294 gint flx_dns_packet_consume_uint16(flxDnsPacket *p, guint16 *ret_v) {
298 if (p->rindex + sizeof(guint16) > p->size)
301 *ret_v = g_ntohs(*((guint16*) (FLX_DNS_PACKET_DATA(p) + p->rindex)));
302 p->rindex += sizeof(guint16);
307 gint flx_dns_packet_consume_uint32(flxDnsPacket *p, guint32 *ret_v) {
311 if (p->rindex + sizeof(guint32) > p->size)
314 *ret_v = g_ntohl(*((guint32*) (FLX_DNS_PACKET_DATA(p) + p->rindex)));
315 p->rindex += sizeof(guint32);
320 gint flx_dns_packet_consume_bytes(flxDnsPacket *p, gpointer ret_data, guint l) {
325 if (p->rindex + l > p->size)
328 memcpy(ret_data, FLX_DNS_PACKET_DATA(p) + p->rindex, l);
334 gint flx_dns_packet_consume_string(flxDnsPacket *p, gchar *ret_string, guint l) {
338 g_assert(ret_string);
341 if (p->rindex >= p->size)
344 k = FLX_DNS_PACKET_DATA(p)[p->rindex];
346 if (p->rindex+1+k > p->size)
352 memcpy(ret_string, FLX_DNS_PACKET_DATA(p)+p->rindex+1, l-1);
362 gconstpointer flx_dns_packet_get_rptr(flxDnsPacket *p) {
365 if (p->rindex > p->size)
368 return FLX_DNS_PACKET_DATA(p) + p->rindex;
371 gint flx_dns_packet_skip(flxDnsPacket *p, guint length) {
374 if (p->rindex + length > p->size)
381 flxRecord* flx_dns_packet_consume_record(flxDnsPacket *p, gboolean *ret_cache_flush) {
382 gchar name[257], buf[257];
391 g_assert(ret_cache_flush);
393 /* g_message("consume_record()"); */
395 if (flx_dns_packet_consume_name(p, name, sizeof(name)) < 0 ||
396 flx_dns_packet_consume_uint16(p, &type) < 0 ||
397 flx_dns_packet_consume_uint16(p, &class) < 0 ||
398 flx_dns_packet_consume_uint32(p, &ttl) < 0 ||
399 flx_dns_packet_consume_uint16(p, &rdlength) < 0 ||
400 p->rindex + rdlength > p->size)
404 /* g_message("name = %s, rdlength = %u", name, rdlength); */
406 start = flx_dns_packet_get_rptr(p);
408 r = flx_record_new_full(name, class, type);
411 case FLX_DNS_TYPE_PTR:
412 case FLX_DNS_TYPE_CNAME:
414 /* g_message("ptr"); */
416 if (flx_dns_packet_consume_name(p, buf, sizeof(buf)) < 0)
419 r->data.ptr.name = g_strdup(buf);
423 case FLX_DNS_TYPE_SRV:
425 /* g_message("srv"); */
427 if (flx_dns_packet_consume_uint16(p, &r->data.srv.priority) < 0 ||
428 flx_dns_packet_consume_uint16(p, &r->data.srv.weight) < 0 ||
429 flx_dns_packet_consume_uint16(p, &r->data.srv.port) < 0 ||
430 flx_dns_packet_consume_name(p, buf, sizeof(buf)) < 0)
433 r->data.srv.name = g_strdup(buf);
436 case FLX_DNS_TYPE_HINFO:
438 /* g_message("hinfo"); */
440 if (flx_dns_packet_consume_string(p, buf, sizeof(buf)) < 0)
443 r->data.hinfo.cpu = g_strdup(buf);
445 if (flx_dns_packet_consume_string(p, buf, sizeof(buf)) < 0)
448 r->data.hinfo.os = g_strdup(buf);
451 case FLX_DNS_TYPE_TXT:
453 /* g_message("txt"); */
456 r->data.txt.string_list = flx_string_list_parse(flx_dns_packet_get_rptr(p), rdlength);
458 if (flx_dns_packet_skip(p, rdlength) < 0)
461 r->data.txt.string_list = NULL;
467 /* g_message("A"); */
469 if (flx_dns_packet_consume_bytes(p, &r->data.a.address, sizeof(flxIPv4Address)) < 0)
474 case FLX_DNS_TYPE_AAAA:
476 /* g_message("aaaa"); */
478 if (flx_dns_packet_consume_bytes(p, &r->data.aaaa.address, sizeof(flxIPv6Address)) < 0)
485 /* g_message("generic"); */
489 r->data.generic.data = g_memdup(flx_dns_packet_get_rptr(p), rdlength);
491 if (flx_dns_packet_skip(p, rdlength) < 0)
498 /* g_message("%i == %u ?", (guint8*) flx_dns_packet_get_rptr(p) - (guint8*) start, rdlength); */
500 /* Check if we read enough data */
501 if ((guint8*) flx_dns_packet_get_rptr(p) - (guint8*) start != rdlength)
504 *ret_cache_flush = !!(class & MDNS_CACHE_FLUSH);
505 class &= ~ MDNS_CACHE_FLUSH;
518 flxKey* flx_dns_packet_consume_key(flxDnsPacket *p) {
524 if (flx_dns_packet_consume_name(p, name, sizeof(name)) < 0 ||
525 flx_dns_packet_consume_uint16(p, &type) < 0 ||
526 flx_dns_packet_consume_uint16(p, &class) < 0)
529 class &= ~ MDNS_CACHE_FLUSH;
531 return flx_key_new(name, class, type);
534 guint8* flx_dns_packet_append_key(flxDnsPacket *p, flxKey *k) {
543 if (!(t = flx_dns_packet_append_name(p, k->name)) ||
544 !flx_dns_packet_append_uint16(p, k->type) ||
545 !flx_dns_packet_append_uint16(p, k->class)) {
553 guint8* flx_dns_packet_append_record(flxDnsPacket *p, flxRecord *r, gboolean cache_flush) {
554 guint8 *t, *l, *start;
562 if (!(t = flx_dns_packet_append_name(p, r->key->name)) ||
563 !flx_dns_packet_append_uint16(p, r->key->type) ||
564 !flx_dns_packet_append_uint16(p, cache_flush ? (r->key->class | MDNS_CACHE_FLUSH) : (r->key->class &~ MDNS_CACHE_FLUSH)) ||
565 !flx_dns_packet_append_uint32(p, r->ttl) ||
566 !(l = flx_dns_packet_append_uint16(p, 0)))
569 start = flx_dns_packet_extend(p, 0);
571 switch (r->key->type) {
573 case FLX_DNS_TYPE_PTR:
574 case FLX_DNS_TYPE_CNAME :
576 if (!(flx_dns_packet_append_name(p, r->data.ptr.name)))
581 case FLX_DNS_TYPE_SRV:
583 if (!flx_dns_packet_append_uint16(p, r->data.srv.priority) ||
584 !flx_dns_packet_append_uint16(p, r->data.srv.weight) ||
585 !flx_dns_packet_append_uint16(p, r->data.srv.port) ||
586 !flx_dns_packet_append_name(p, r->data.srv.name))
591 case FLX_DNS_TYPE_HINFO:
592 if (!flx_dns_packet_append_string(p, r->data.hinfo.cpu) ||
593 !flx_dns_packet_append_string(p, r->data.hinfo.os))
598 case FLX_DNS_TYPE_TXT: {
603 size = flx_string_list_serialize(r->data.txt.string_list, NULL, 0);
605 /* g_message("appending string: %u %p", size, r->data.txt.string_list); */
607 if (!(data = flx_dns_packet_extend(p, size)))
610 flx_string_list_serialize(r->data.txt.string_list, data, size);
617 if (!flx_dns_packet_append_bytes(p, &r->data.a.address, sizeof(r->data.a.address)))
622 case FLX_DNS_TYPE_AAAA:
624 if (!flx_dns_packet_append_bytes(p, &r->data.aaaa.address, sizeof(r->data.aaaa.address)))
631 if (r->data.generic.size &&
632 flx_dns_packet_append_bytes(p, r->data.generic.data, r->data.generic.size))
641 size = flx_dns_packet_extend(p, 0) - start;
642 g_assert(size <= 0xFFFF);
644 /* g_message("appended %u", size); */
646 * (guint16*) l = g_htons((guint16) size);
656 gboolean flx_dns_packet_is_empty(flxDnsPacket *p) {
659 return p->size <= FLX_DNS_PACKET_HEADER_SIZE;