summaryrefslogtreecommitdiff
path: root/tinysvcmdns.c
diff options
context:
space:
mode:
Diffstat (limited to 'tinysvcmdns.c')
-rw-r--r--tinysvcmdns.c2429
1 files changed, 1203 insertions, 1226 deletions
diff --git a/tinysvcmdns.c b/tinysvcmdns.c
index 8c03b38..bdb6c09 100644
--- a/tinysvcmdns.c
+++ b/tinysvcmdns.c
@@ -34,18 +34,16 @@
#include "common.h"
#define DEBUG_PRINTF(...) debug(1, __VA_ARGS__)
-#define log_message(level, ...) \
- do { \
- switch(level) \
- { \
- case LOG_ERR: \
- warn(__VA_ARGS__); \
- break; \
- default: \
- debug(1, __VA_ARGS__); \
- } \
- } while (0)
-
+#define log_message(level, ...) \
+ do { \
+ switch (level) { \
+ case LOG_ERR: \
+ warn(__VA_ARGS__); \
+ break; \
+ default: \
+ debug(1, __VA_ARGS__); \
+ } \
+ } while (0)
//******************************************************//
// mdns.c //
@@ -63,311 +61,320 @@
#include <netinet/in.h>
#endif
-// See RFC 6762 Section 10 for an account of two TTLs -- 120 seconds for rrs with a host name as the record's name
+// See RFC 6762 Section 10 for an account of two TTLs -- 120 seconds for rrs with a host name as the
+// record's name
// or a host name in the record's rdata
// 75 minutes for everything else.
// https://tools.ietf.org/html/rfc6762
-#define DEFAULT_TTL_FOR_RECORD_WITH_HOSTNAME 120
-#define DEFAULT_TTL 4500
+#define DEFAULT_TTL_FOR_RECORD_WITH_HOSTNAME 120
+#define DEFAULT_TTL 4500
struct name_comp {
- uint8_t *label; // label
- size_t pos; // position in msg
+ uint8_t *label; // label
+ size_t pos; // position in msg
- struct name_comp *next;
+ struct name_comp *next;
};
// ----- label functions -----
// duplicates a name
inline uint8_t *dup_nlabel(const uint8_t *n) {
- assert(n[0] <= 63); // prevent mis-use
- return (uint8_t *) strdup((char *) n);
+ assert(n[0] <= 63); // prevent mis-use
+ return (uint8_t *)strdup((char *)n);
}
// duplicates a label
uint8_t *dup_label(const uint8_t *label) {
- int len = *label + 1;
- if (len > 63)
- return NULL;
- uint8_t *newlabel = malloc(len + 1);
- strncpy((char *) newlabel, (char *) label, len);
- newlabel[len] = '\0';
- return newlabel;
+ int len = *label + 1;
+ if (len > 63)
+ return NULL;
+ uint8_t *newlabel = malloc(len + 1);
+ strncpy((char *)newlabel, (char *)label, len);
+ newlabel[len] = '\0';
+ return newlabel;
}
uint8_t *join_nlabel(const uint8_t *n1, const uint8_t *n2) {
- int len1, len2;
- uint8_t *s;
+ int len1, len2;
+ uint8_t *s;
- assert(n1[0] <= 63 && n2[0] <= 63); // detect misuse
+ assert(n1[0] <= 63 && n2[0] <= 63); // detect misuse
- len1 = strlen((char *) n1);
- len2 = strlen((char *) n2);
+ len1 = strlen((char *)n1);
+ len2 = strlen((char *)n2);
- s = malloc(len1 + len2 + 1);
- strncpy((char *) s, (char *) n1, len1);
- strncpy((char *) s+len1, (char *) n2, len2);
- s[len1 + len2] = '\0';
- return s;
+ s = malloc(len1 + len2 + 1);
+ strncpy((char *)s, (char *)n1, len1);
+ strncpy((char *)s + len1, (char *)n2, len2);
+ s[len1 + len2] = '\0';
+ return s;
}
// returns a human-readable name label in dotted form
char *nlabel_to_str(const uint8_t *name) {
- char *label, *labelp;
- const uint8_t *p;
+ char *label, *labelp;
+ const uint8_t *p;
- assert(name != NULL);
+ assert(name != NULL);
- label = labelp = malloc(256);
+ label = labelp = malloc(256);
- for (p = name; *p; p++) {
- strncpy(labelp, (char *) p + 1, *p);
- labelp += *p;
- *labelp = '.';
- labelp++;
+ for (p = name; *p; p++) {
+ strncpy(labelp, (char *)p + 1, *p);
+ labelp += *p;
+ *labelp = '.';
+ labelp++;
- p += *p;
- }
+ p += *p;
+ }
- *labelp = '\0';
+ *labelp = '\0';
- return label;
+ return label;
}
// returns the length of a label field
// does NOT uncompress the field, so it could be as small as 2 bytes
// or 1 for the root
static size_t label_len(uint8_t *pkt_buf, size_t pkt_len, size_t off) {
- uint8_t *p;
- uint8_t *e = pkt_buf + pkt_len;
- size_t len = 0;
-
- for (p = pkt_buf + off; p < e; p++) {
- if (*p == 0) {
- return len + 1;
- } else if ((*p & 0xC0) == 0xC0) {
- return len + 2;
- } else {
- len += *p + 1;
- p += *p;
- }
- }
-
- return len;
+ uint8_t *p;
+ uint8_t *e = pkt_buf + pkt_len;
+ size_t len = 0;
+
+ for (p = pkt_buf + off; p < e; p++) {
+ if (*p == 0) {
+ return len + 1;
+ } else if ((*p & 0xC0) == 0xC0) {
+ return len + 2;
+ } else {
+ len += *p + 1;
+ p += *p;
+ }
+ }
+
+ return len;
}
// creates a label
// free() after use
uint8_t *create_label(const char *txt) {
- int len;
- uint8_t *s;
+ int len;
+ uint8_t *s;
- assert(txt != NULL);
- len = strlen(txt);
- if (len > 63)
- return NULL;
+ assert(txt != NULL);
+ len = strlen(txt);
+ if (len > 63)
+ return NULL;
- s = malloc(len + 2);
- s[0] = len;
- strncpy((char *) s + 1, txt, len);
- s[len + 1] = '\0';
+ s = malloc(len + 2);
+ s[0] = len;
+ strncpy((char *)s + 1, txt, len);
+ s[len + 1] = '\0';
- return s;
+ return s;
}
// creates a uncompressed name label given a DNS name like "apple.b.com"
// free() after use
uint8_t *create_nlabel(const char *name) {
- char *label;
- char *p, *e, *lenpos;
- int len = 0;
+ char *label;
+ char *p, *e, *lenpos;
+ int len = 0;
- assert(name != NULL);
+ assert(name != NULL);
- len = strlen(name);
- label = malloc(len + 1 + 1);
- if (label == NULL)
- return NULL;
+ len = strlen(name);
+ label = malloc(len + 1 + 1);
+ if (label == NULL)
+ return NULL;
- strncpy((char *) label + 1, name, len);
- label[len + 1] = '\0';
+ strncpy((char *)label + 1, name, len);
+ label[len + 1] = '\0';
- p = label;
- e = p + len;
- lenpos = p;
+ p = label;
+ e = p + len;
+ lenpos = p;
- while (p < e) {
- *lenpos = 0;
- char *dot = memchr(p + 1, '.', e - p - 1);
- if (dot == NULL)
- dot = e + 1;
- *lenpos = dot - p - 1;
+ while (p < e) {
+ *lenpos = 0;
+ char *dot = memchr(p + 1, '.', e - p - 1);
+ if (dot == NULL)
+ dot = e + 1;
+ *lenpos = dot - p - 1;
- p = dot;
- lenpos = dot;
- }
+ p = dot;
+ lenpos = dot;
+ }
- return (uint8_t *) label;
+ return (uint8_t *)label;
}
// copies a label from the buffer into a newly-allocated string
// free() after use
static uint8_t *copy_label(uint8_t *pkt_buf, size_t pkt_len, size_t off) {
- int len;
+ int len;
- if (off > pkt_len)
- return NULL;
+ if (off > pkt_len)
+ return NULL;
- len = pkt_buf[off] + 1;
- if (off + len > pkt_len) {
- DEBUG_PRINTF("label length exceeds packet buffer\n");
- return NULL;
- }
+ len = pkt_buf[off] + 1;
+ if (off + len > pkt_len) {
+ DEBUG_PRINTF("label length exceeds packet buffer\n");
+ return NULL;
+ }
- return dup_label(pkt_buf + off);
+ return dup_label(pkt_buf + off);
}
// uncompresses a name
// free() after use
static uint8_t *uncompress_nlabel(uint8_t *pkt_buf, size_t pkt_len, size_t off) {
- uint8_t *p;
- uint8_t *e = pkt_buf + pkt_len;
- size_t len = 0;
- char *str, *sp;
- if (off >= pkt_len)
- return NULL;
-
- // calculate length of uncompressed label
- for (p = pkt_buf + off; *p && p < e; p++) {
- size_t llen = 0;
- if ((*p & 0xC0) == 0xC0) {
- uint8_t *p2 = pkt_buf + (((p[0] & ~0xC0) << 8) | p[1]);
- llen = *p2 + 1;
- p = p2 + llen - 1;
- } else {
- llen = *p + 1;
- p += llen - 1;
- }
- len += llen;
- }
-
- str = sp = malloc(len + 1);
- if (str == NULL)
- return NULL;
-
- // FIXME: must merge this with above code
- for (p = pkt_buf + off; *p && p < e; p++) {
- size_t llen = 0;
- if ((*p & 0xC0) == 0xC0) {
- uint8_t *p2 = pkt_buf + (((p[0] & ~0xC0) << 8) | p[1]);
- llen = *p2 + 1;
- strncpy(sp, (char *) p2, llen);
- p = p2 + llen - 1;
- } else {
- llen = *p + 1;
- strncpy(sp, (char *) p, llen);
- p += llen - 1;
- }
- sp += llen;
- }
- *sp = '\0';
-
- return (uint8_t *) str;
+ uint8_t *p;
+ uint8_t *e = pkt_buf + pkt_len;
+ size_t len = 0;
+ char *str, *sp;
+ if (off >= pkt_len)
+ return NULL;
+
+ // calculate length of uncompressed label
+ for (p = pkt_buf + off; *p && p < e; p++) {
+ size_t llen = 0;
+ if ((*p & 0xC0) == 0xC0) {
+ uint8_t *p2 = pkt_buf + (((p[0] & ~0xC0) << 8) | p[1]);
+ llen = *p2 + 1;
+ p = p2 + llen - 1;
+ } else {
+ llen = *p + 1;
+ p += llen - 1;
+ }
+ len += llen;
+ }
+
+ str = sp = malloc(len + 1);
+ if (str == NULL)
+ return NULL;
+
+ // FIXME: must merge this with above code
+ for (p = pkt_buf + off; *p && p < e; p++) {
+ size_t llen = 0;
+ if ((*p & 0xC0) == 0xC0) {
+ uint8_t *p2 = pkt_buf + (((p[0] & ~0xC0) << 8) | p[1]);
+ llen = *p2 + 1;
+ strncpy(sp, (char *)p2, llen);
+ p = p2 + llen - 1;
+ } else {
+ llen = *p + 1;
+ strncpy(sp, (char *)p, llen);
+ p += llen - 1;
+ }
+ sp += llen;
+ }
+ *sp = '\0';
+
+ return (uint8_t *)str;
}
// ----- RR list & group functions -----
const char *rr_get_type_name(enum rr_type type) {
- switch (type) {
- case RR_A: return "A";
- case RR_PTR: return "PTR";
- case RR_TXT: return "TXT";
- case RR_AAAA: return "AAAA";
- case RR_SRV: return "SRV";
- case RR_NSEC: return "NSEC";
- case RR_ANY: return "ANY";
- }
- return NULL;
+ switch (type) {
+ case RR_A:
+ return "A";
+ case RR_PTR:
+ return "PTR";
+ case RR_TXT:
+ return "TXT";
+ case RR_AAAA:
+ return "AAAA";
+ case RR_SRV:
+ return "SRV";
+ case RR_NSEC:
+ return "NSEC";
+ case RR_ANY:
+ return "ANY";
+ }
+ return NULL;
}
void rr_entry_destroy(struct rr_entry *rr) {
- struct rr_data_txt *txt_rec;
- assert(rr);
-
- // check rr_type and free data elements
- switch (rr->type) {
- case RR_PTR:
- if (rr->data.PTR.name)
- free(rr->data.PTR.name);
- // don't free entry
- break;
-
- case RR_TXT:
- txt_rec = &rr->data.TXT;
- while (txt_rec) {
- struct rr_data_txt *next = txt_rec->next;
- if (txt_rec->txt)
- free(txt_rec->txt);
-
- // only free() if it wasn't part of the struct
- if (txt_rec != &rr->data.TXT)
- free(txt_rec);
-
- txt_rec = next;
- }
- break;
-
- case RR_SRV:
- if (rr->data.SRV.target)
- free(rr->data.SRV.target);
- break;
-
- default:
- // nothing to free
- break;
- }
-
- free(rr->name);
- free(rr);
+ struct rr_data_txt *txt_rec;
+ assert(rr);
+
+ // check rr_type and free data elements
+ switch (rr->type) {
+ case RR_PTR:
+ if (rr->data.PTR.name)
+ free(rr->data.PTR.name);
+ // don't free entry
+ break;
+
+ case RR_TXT:
+ txt_rec = &rr->data.TXT;
+ while (txt_rec) {
+ struct rr_data_txt *next = txt_rec->next;
+ if (txt_rec->txt)
+ free(txt_rec->txt);
+
+ // only free() if it wasn't part of the struct
+ if (txt_rec != &rr->data.TXT)
+ free(txt_rec);
+
+ txt_rec = next;
+ }
+ break;
+
+ case RR_SRV:
+ if (rr->data.SRV.target)
+ free(rr->data.SRV.target);
+ break;
+
+ default:
+ // nothing to free
+ break;
+ }
+
+ free(rr->name);
+ free(rr);
}
// destroys an RR list (and optionally, items)
void rr_list_destroy(struct rr_list *rr, char destroy_items) {
- struct rr_list *rr_next;
-
- for (; rr; rr = rr_next) {
- rr_next = rr->next;
- if (destroy_items)
- rr_entry_destroy(rr->e);
- free(rr);
- }
+ struct rr_list *rr_next;
+
+ for (; rr; rr = rr_next) {
+ rr_next = rr->next;
+ if (destroy_items)
+ rr_entry_destroy(rr->e);
+ free(rr);
+ }
}
int rr_list_count(struct rr_list *rr) {
- int i = 0;
- for (; rr; i++, rr = rr->next);
- return i;
+ int i = 0;
+ for (; rr; i++, rr = rr->next)
+ ;
+ return i;
}
struct rr_entry *rr_list_remove(struct rr_list **rr_head, struct rr_entry *rr) {
- struct rr_list *le = *rr_head, *pe = NULL;
- for (; le; le = le->next) {
- if (le->e == rr) {
- if (pe == NULL) {
- *rr_head = le->next;
- free(le);
- return rr;
- } else {
- pe->next = le->next;
- free(le);
- return rr;
- }
- }
- pe = le;
- }
- return NULL;
+ struct rr_list *le = *rr_head, *pe = NULL;
+ for (; le; le = le->next) {
+ if (le->e == rr) {
+ if (pe == NULL) {
+ *rr_head = le->next;
+ free(le);
+ return rr;
+ } else {
+ pe->next = le->next;
+ free(le);
+ return rr;
+ }
+ }
+ pe = le;
+ }
+ return NULL;
}
// appends an rr_entry to an RR list
@@ -375,650 +382,642 @@ struct rr_entry *rr_list_remove(struct rr_list **rr_head, struct rr_entry *rr) {
// RRs are compared by memory location - not its contents
// return value of 0 means item not added
int rr_list_append(struct rr_list **rr_head, struct rr_entry *rr) {
- struct rr_list *node = malloc(sizeof(struct rr_list));
- node->e = rr;
- node->next = NULL;
-
- if (*rr_head == NULL) {
- *rr_head = node;
- } else {
- struct rr_list *e = *rr_head, *taile;
- for (; e; e = e->next) {
- // already in list - don't add
- if (e->e == rr) {
- free(node);
- return 0;
- }
- if (e->next == NULL)
- taile = e;
- }
- taile->next = node;
- }
- return 1;
+ struct rr_list *node = malloc(sizeof(struct rr_list));
+ node->e = rr;
+ node->next = NULL;
+
+ if (*rr_head == NULL) {
+ *rr_head = node;
+ } else {
+ struct rr_list *e = *rr_head, *taile;
+ for (; e; e = e->next) {
+ // already in list - don't add
+ if (e->e == rr) {
+ free(node);
+ return 0;
+ }
+ if (e->next == NULL)
+ taile = e;
+ }
+ taile->next = node;
+ }
+ return 1;
}
-#define FILL_RR_ENTRY(rr, _name, _type) \
- rr->name = _name; \
- rr->type = _type; \
- rr->ttl = DEFAULT_TTL; \
- rr->cache_flush = 1; \
- rr->rr_class = 1;
+#define FILL_RR_ENTRY(rr, _name, _type) \
+ rr->name = _name; \
+ rr->type = _type; \
+ rr->ttl = DEFAULT_TTL; \
+ rr->cache_flush = 1; \
+ rr->rr_class = 1;
struct rr_entry *rr_create_a(uint8_t *name, uint32_t addr) {
- DECL_MALLOC_ZERO_STRUCT(rr, rr_entry);
- FILL_RR_ENTRY(rr, name, RR_A);
- rr->data.A.addr = addr;
- rr->ttl = DEFAULT_TTL_FOR_RECORD_WITH_HOSTNAME; // 120 seconds -- see RFC 6762 Section 10
- return rr;
+ DECL_MALLOC_ZERO_STRUCT(rr, rr_entry);
+ FILL_RR_ENTRY(rr, name, RR_A);
+ rr->data.A.addr = addr;
+ rr->ttl = DEFAULT_TTL_FOR_RECORD_WITH_HOSTNAME; // 120 seconds -- see RFC 6762 Section 10
+ return rr;
}
struct rr_entry *rr_create_aaaa(uint8_t *name, struct in6_addr *addr) {
- DECL_MALLOC_ZERO_STRUCT(rr, rr_entry);
- FILL_RR_ENTRY(rr, name, RR_AAAA);
- rr->data.AAAA.addr = addr;
- rr->ttl = DEFAULT_TTL_FOR_RECORD_WITH_HOSTNAME; // 120 seconds -- see RFC 6762 Section 10
- return rr;
+ DECL_MALLOC_ZERO_STRUCT(rr, rr_entry);
+ FILL_RR_ENTRY(rr, name, RR_AAAA);
+ rr->data.AAAA.addr = addr;
+ rr->ttl = DEFAULT_TTL_FOR_RECORD_WITH_HOSTNAME; // 120 seconds -- see RFC 6762 Section 10
+ return rr;
}
struct rr_entry *rr_create_srv(uint8_t *name, uint16_t port, uint8_t *target) {
- DECL_MALLOC_ZERO_STRUCT(rr, rr_entry);
- FILL_RR_ENTRY(rr, name, RR_SRV);
- rr->data.SRV.port = port;
- rr->data.SRV.target = target;
- return rr;
+ DECL_MALLOC_ZERO_STRUCT(rr, rr_entry);
+ FILL_RR_ENTRY(rr, name, RR_SRV);
+ rr->data.SRV.port = port;
+ rr->data.SRV.target = target;
+ return rr;
}
struct rr_entry *rr_create_ptr(uint8_t *name, struct rr_entry *d_rr) {
- DECL_MALLOC_ZERO_STRUCT(rr, rr_entry);
- FILL_RR_ENTRY(rr, name, RR_PTR);
- rr->cache_flush = 0; // PTRs shouldn't have their cache flush bit set
- rr->data.PTR.entry = d_rr;
- return rr;
+ DECL_MALLOC_ZERO_STRUCT(rr, rr_entry);
+ FILL_RR_ENTRY(rr, name, RR_PTR);
+ rr->cache_flush = 0; // PTRs shouldn't have their cache flush bit set
+ rr->data.PTR.entry = d_rr;
+ return rr;
}
struct rr_entry *rr_create(uint8_t *name, enum rr_type type) {
- DECL_MALLOC_ZERO_STRUCT(rr, rr_entry);
- FILL_RR_ENTRY(rr, name, type);
- return rr;
+ DECL_MALLOC_ZERO_STRUCT(rr, rr_entry);
+ FILL_RR_ENTRY(rr, name, type);
+ return rr;
}
void rr_set_nsec(struct rr_entry *rr_nsec, enum rr_type type) {
- assert(rr_nsec->type = RR_NSEC);
- assert((type / 8) < sizeof(rr_nsec->data.NSEC.bitmap));
+ assert(rr_nsec->type = RR_NSEC);
+ assert((type / 8) < sizeof(rr_nsec->data.NSEC.bitmap));
- rr_nsec->data.NSEC.bitmap[ type / 8 ] = 1 << (7 - (type % 8));
+ rr_nsec->data.NSEC.bitmap[type / 8] = 1 << (7 - (type % 8));
}
void rr_add_txt(struct rr_entry *rr_txt, const char *txt) {
- struct rr_data_txt *txt_rec;
- assert(rr_txt->type == RR_TXT);
+ struct rr_data_txt *txt_rec;
+ assert(rr_txt->type == RR_TXT);
- txt_rec = &rr_txt->data.TXT;
+ txt_rec = &rr_txt->data.TXT;
- // is current data filled?
- if (txt_rec->txt == NULL) {
- txt_rec->txt = create_label(txt);
- return;
- }
+ // is current data filled?
+ if (txt_rec->txt == NULL) {
+ txt_rec->txt = create_label(txt);
+ return;
+ }
- // find the last node
- for (; txt_rec->next; txt_rec = txt_rec->next);
+ // find the last node
+ for (; txt_rec->next; txt_rec = txt_rec->next)
+ ;
- // create a new empty node
- txt_rec->next = malloc(sizeof(struct rr_data_txt));
+ // create a new empty node
+ txt_rec->next = malloc(sizeof(struct rr_data_txt));
- txt_rec = txt_rec->next;
- txt_rec->txt = create_label(txt);
- txt_rec->next = NULL;
+ txt_rec = txt_rec->next;
+ txt_rec->txt = create_label(txt);
+ txt_rec->next = NULL;
}
// adds a record to an rr_group
void rr_group_add(struct rr_group **group, struct rr_entry *rr) {
- struct rr_group *g;
+ struct rr_group *g;
- assert(rr != NULL);
+ assert(rr != NULL);
- if (*group) {
- g = rr_group_find(*group, rr->name);
- if (g) {
- rr_list_append(&g->rr, rr);
- return;
- }
- }
+ if (*group) {
+ g = rr_group_find(*group, rr->name);
+ if (g) {
+ rr_list_append(&g->rr, rr);
+ return;
+ }
+ }
- MALLOC_ZERO_STRUCT(g, rr_group);
- g->name = dup_nlabel(rr->name);
- rr_list_append(&g->rr, rr);
+ MALLOC_ZERO_STRUCT(g, rr_group);
+ g->name = dup_nlabel(rr->name);
+ rr_list_append(&g->rr, rr);
- // prepend to list
- g->next = *group;
- *group = g;
+ // prepend to list
+ g->next = *group;
+ *group = g;
}
// finds a rr_group matching the given name
-struct rr_group *rr_group_find(struct rr_group* g, uint8_t *name) {
- for (; g; g = g->next) {
- if (cmp_nlabel(g->name, name) == 0)
- return g;
- }
- return NULL;
+struct rr_group *rr_group_find(struct rr_group *g, uint8_t *name) {
+ for (; g; g = g->next) {
+ if (cmp_nlabel(g->name, name) == 0)
+ return g;
+ }
+ return NULL;
}
struct rr_entry *rr_entry_find(struct rr_list *rr_list, uint8_t *name, uint16_t type) {
- struct rr_list *rr = rr_list;
- for (; rr; rr = rr->next) {
- if (rr->e->type == type && cmp_nlabel(rr->e->name, name) == 0)
- return rr->e;
- }
- return NULL;
+ struct rr_list *rr = rr_list;
+ for (; rr; rr = rr->next) {
+ if (rr->e->type == type && cmp_nlabel(rr->e->name, name) == 0)
+ return rr->e;
+ }
+ return NULL;
}
// looks for a matching entry in rr_list
// if entry is a PTR, we need to check if the PTR target also matches
struct rr_entry *rr_entry_match(struct rr_list *rr_list, struct rr_entry *entry) {
- struct rr_list *rr = rr_list;
- for (; rr; rr = rr->next) {
- if (rr->e->type == entry->type && cmp_nlabel(rr->e->name, entry->name) == 0) {
- if (entry->type != RR_PTR) {
- return rr->e;
- } else if (cmp_nlabel(MDNS_RR_GET_PTR_NAME(entry), MDNS_RR_GET_PTR_NAME(rr->e)) == 0) {
- // if it's a PTR, we need to make sure PTR target also matches
- return rr->e;
- }
- }
- }
- return NULL;
+ struct rr_list *rr = rr_list;
+ for (; rr; rr = rr->next) {
+ if (rr->e->type == entry->type && cmp_nlabel(rr->e->name, entry->name) == 0) {
+ if (entry->type != RR_PTR) {
+ return rr->e;
+ } else if (cmp_nlabel(MDNS_RR_GET_PTR_NAME(entry), MDNS_RR_GET_PTR_NAME(rr->e)) == 0) {
+ // if it's a PTR, we need to make sure PTR target also matches
+ return rr->e;
+ }
+ }
+ }
+ return NULL;
}
void rr_group_destroy(struct rr_group *group) {
- struct rr_group *g = group;
-
- while (g) {
- struct rr_group *nextg = g->next;
- free(g->name);
- rr_list_destroy(g->rr, 1);
- free(g);
- g = nextg;
- }
+ struct rr_group *g = group;
+
+ while (g) {
+ struct rr_group *nextg = g->next;
+ free(g->name);
+ rr_list_destroy(g->rr, 1);
+ free(g);
+ g = nextg;
+ }
}
uint8_t *mdns_write_u16(uint8_t *ptr, const uint16_t v) {
- *ptr++ = (uint8_t) (v >> 8) & 0xFF;
- *ptr++ = (uint8_t) (v >> 0) & 0xFF;
- return ptr;
+ *ptr++ = (uint8_t)(v >> 8) & 0xFF;
+ *ptr++ = (uint8_t)(v >> 0) & 0xFF;
+ return ptr;
}
uint8_t *mdns_write_u32(uint8_t *ptr, const uint32_t v) {
- *ptr++ = (uint8_t) (v >> 24) & 0xFF;
- *ptr++ = (uint8_t) (v >> 16) & 0xFF;
- *ptr++ = (uint8_t) (v >> 8) & 0xFF;
- *ptr++ = (uint8_t) (v >> 0) & 0xFF;
- return ptr;
+ *ptr++ = (uint8_t)(v >> 24) & 0xFF;
+ *ptr++ = (uint8_t)(v >> 16) & 0xFF;
+ *ptr++ = (uint8_t)(v >> 8) & 0xFF;
+ *ptr++ = (uint8_t)(v >> 0) & 0xFF;
+ return ptr;
}
uint16_t mdns_read_u16(const uint8_t *ptr) {
- return ((ptr[0] & 0xFF) << 8) |
- ((ptr[1] & 0xFF) << 0);
+ return ((ptr[0] & 0xFF) << 8) | ((ptr[1] & 0xFF) << 0);
}
uint32_t mdns_read_u32(const uint8_t *ptr) {
- return ((ptr[0] & 0xFF) << 24) |
- ((ptr[1] & 0xFF) << 16) |
- ((ptr[2] & 0xFF) << 8) |
- ((ptr[3] & 0xFF) << 0);
+ return ((ptr[0] & 0xFF) << 24) | ((ptr[1] & 0xFF) << 16) | ((ptr[2] & 0xFF) << 8) |
+ ((ptr[3] & 0xFF) << 0);
}
// initialize the packet for reply
// clears the packet of list structures but not its list items
void mdns_init_reply(struct mdns_pkt *pkt, uint16_t id) {
- // copy transaction ID
- pkt->id = id;
-
- // response flags
- pkt->flags = MDNS_FLAG_RESP | MDNS_FLAG_AA;
-
- rr_list_destroy(pkt->rr_qn, 0);
- rr_list_destroy(pkt->rr_ans, 0);
- rr_list_destroy(pkt->rr_auth, 0);
- rr_list_destroy(pkt->rr_add, 0);
-
- pkt->rr_qn = NULL;
- pkt->rr_ans = NULL;
- pkt->rr_auth = NULL;
- pkt->rr_add = NULL;
-
- pkt->num_qn = 0;
- pkt->num_ans_rr = 0;
- pkt->num_auth_rr = 0;
- pkt->num_add_rr = 0;
+ // copy transaction ID
+ pkt->id = id;
+
+ // response flags
+ pkt->flags = MDNS_FLAG_RESP | MDNS_FLAG_AA;
+
+ rr_list_destroy(pkt->rr_qn, 0);
+ rr_list_destroy(pkt->rr_ans, 0);
+ rr_list_destroy(pkt->rr_auth, 0);
+ rr_list_destroy(pkt->rr_add, 0);
+
+ pkt->rr_qn = NULL;
+ pkt->rr_ans = NULL;
+ pkt->rr_auth = NULL;
+ pkt->rr_add = NULL;
+
+ pkt->num_qn = 0;
+ pkt->num_ans_rr = 0;
+ pkt->num_auth_rr = 0;
+ pkt->num_add_rr = 0;
}
// destroys an mdns_pkt struct, including its contents
void mdns_pkt_destroy(struct mdns_pkt *p) {
- rr_list_destroy(p->rr_qn, 1);
- rr_list_destroy(p->rr_ans, 1);
- rr_list_destroy(p->rr_auth, 1);
- rr_list_destroy(p->rr_add, 1);
+ rr_list_destroy(p->rr_qn, 1);
+ rr_list_destroy(p->rr_ans, 1);
+ rr_list_destroy(p->rr_auth, 1);
+ rr_list_destroy(p->rr_add, 1);
- free(p);
+ free(p);
}
-
// parse the MDNS questions section
// stores the parsed data in the given mdns_pkt struct
-static size_t mdns_parse_qn(uint8_t *pkt_buf, size_t pkt_len, size_t off,
- struct mdns_pkt *pkt) {
- const uint8_t *p = pkt_buf + off;
- struct rr_entry *rr;
- uint8_t *name;
+static size_t mdns_parse_qn(uint8_t *pkt_buf, size_t pkt_len, size_t off, struct mdns_pkt *pkt) {
+ const uint8_t *p = pkt_buf + off;
+ struct rr_entry *rr;
+ uint8_t *name;
- assert(pkt != NULL);
+ assert(pkt != NULL);
- rr = malloc(sizeof(struct rr_entry));
- memset(rr, 0, sizeof(struct rr_entry));
+ rr = malloc(sizeof(struct rr_entry));
+ memset(rr, 0, sizeof(struct rr_entry));
- name = uncompress_nlabel(pkt_buf, pkt_len, off);
- p += label_len(pkt_buf, pkt_len, off);
- rr->name = name;
+ name = uncompress_nlabel(pkt_buf, pkt_len, off);
+ p += label_len(pkt_buf, pkt_len, off);
+ rr->name = name;
- rr->type = mdns_read_u16(p);
- p += sizeof(uint16_t);
+ rr->type = mdns_read_u16(p);
+ p += sizeof(uint16_t);
- rr->unicast_query = (*p & 0x80) == 0x80;
- rr->rr_class = mdns_read_u16(p) & ~0x80;
- p += sizeof(uint16_t);
+ rr->unicast_query = (*p & 0x80) == 0x80;
+ rr->rr_class = mdns_read_u16(p) & ~0x80;
+ p += sizeof(uint16_t);
- rr_list_append(&pkt->rr_qn, rr);
+ rr_list_append(&pkt->rr_qn, rr);
- return p - (pkt_buf + off);
+ return p - (pkt_buf + off);
}
// parse the MDNS RR section
// stores the parsed data in the given mdns_pkt struct
-static size_t mdns_parse_rr(uint8_t *pkt_buf, size_t pkt_len, size_t off,
- struct mdns_pkt *pkt) {
- const uint8_t *p = pkt_buf + off;
- const uint8_t *e = pkt_buf + pkt_len;
- struct rr_entry *rr;
- uint8_t *name;
- size_t rr_data_len = 0;
- struct rr_data_txt *txt_rec;
- int parse_error = 0;
-
- assert(pkt != NULL);
-
- if (off > pkt_len)
- return 0;
-
- rr = malloc(sizeof(struct rr_entry));
- memset(rr, 0, sizeof(struct rr_entry));
-
- name = uncompress_nlabel(pkt_buf, pkt_len, off);
- p += label_len(pkt_buf, pkt_len, off);
- rr->name = name;
-
- rr->type = mdns_read_u16(p);
- p += sizeof(uint16_t);
-
- rr->cache_flush = (*p & 0x80) == 0x80;
- rr->rr_class = mdns_read_u16(p) & ~0x80;
- p += sizeof(uint16_t);
-
- rr->ttl = mdns_read_u32(p);
- p += sizeof(uint32_t);
-
- // RR data
- rr_data_len = mdns_read_u16(p);
- p += sizeof(uint16_t);
-
- if (p + rr_data_len > e) {
- DEBUG_PRINTF("rr_data_len goes beyond packet buffer: %lu > %lu\n", rr_data_len, e - p);
- rr_entry_destroy(rr);
- return 0;
- }
-
- e = p + rr_data_len;
-
- // see if we can parse the RR data
- switch (rr->type) {
- case RR_A:
- if (rr_data_len < sizeof(uint32_t)) {
- DEBUG_PRINTF("invalid rr_data_len=%lu for A record\n", rr_data_len);
- parse_error = 1;
- break;
- }
- rr->data.A.addr = ntohl(mdns_read_u32(p)); /* addr already in net order */
- p += sizeof(uint32_t);
- break;
-
- case RR_AAAA:
- if (rr_data_len < sizeof(struct in6_addr)) {
- DEBUG_PRINTF("invalid rr_data_len=%lu for AAAA record\n", rr_data_len);
- parse_error = 1;
- break;
- }
- rr->data.AAAA.addr = malloc(sizeof(struct in6_addr));
- int i;
- for (i = 0; i < sizeof(struct in6_addr); i++)
- rr->data.AAAA.addr->s6_addr[i] = p[i];
- p += sizeof(struct in6_addr);
- break;
-
- case RR_PTR:
- rr->data.PTR.name = uncompress_nlabel(pkt_buf, pkt_len, p - pkt_buf);
- if (rr->data.PTR.name == NULL) {
- DEBUG_PRINTF("unable to parse/uncompress label for PTR name\n");
- parse_error = 1;
- break;
- }
- p += rr_data_len;
- break;
-
- case RR_TXT:
- txt_rec = &rr->data.TXT;
-
- // not supposed to happen, but we should handle it
- if (rr_data_len == 0) {
- DEBUG_PRINTF("WARN: rr_data_len for TXT is 0\n");
- txt_rec->txt = create_label("");
- break;
- }
-
- while (1) {
- txt_rec->txt = copy_label(pkt_buf, pkt_len, p - pkt_buf);
- if (txt_rec->txt == NULL) {
- DEBUG_PRINTF("unable to copy label for TXT record\n");
- parse_error = 1;
- break;
- }
- p += txt_rec->txt[0] + 1;
-
- if (p >= e)
- break;
-
- // allocate another record
- txt_rec->next = malloc(sizeof(struct rr_data_txt));
- txt_rec = txt_rec->next;
- txt_rec->next = NULL;
- }
- break;
-
- default:
- // skip to end of RR data
- p = e;
- }
-
- // if there was a parse error, destroy partial rr_entry
- if (parse_error) {
- rr_entry_destroy(rr);
- return 0;
- }
-
- rr_list_append(&pkt->rr_ans, rr);
-
- return p - (pkt_buf + off);
+static size_t mdns_parse_rr(uint8_t *pkt_buf, size_t pkt_len, size_t off, struct mdns_pkt *pkt) {
+ const uint8_t *p = pkt_buf + off;
+ const uint8_t *e = pkt_buf + pkt_len;
+ struct rr_entry *rr;
+ uint8_t *name;
+ size_t rr_data_len = 0;
+ struct rr_data_txt *txt_rec;
+ int parse_error = 0;
+
+ assert(pkt != NULL);
+
+ if (off > pkt_len)
+ return 0;
+
+ rr = malloc(sizeof(struct rr_entry));
+ memset(rr, 0, sizeof(struct rr_entry));
+
+ name = uncompress_nlabel(pkt_buf, pkt_len, off);
+ p += label_len(pkt_buf, pkt_len, off);
+ rr->name = name;
+
+ rr->type = mdns_read_u16(p);
+ p += sizeof(uint16_t);
+
+ rr->cache_flush = (*p & 0x80) == 0x80;
+ rr->rr_class = mdns_read_u16(p) & ~0x80;
+ p += sizeof(uint16_t);
+
+ rr->ttl = mdns_read_u32(p);
+ p += sizeof(uint32_t);
+
+ // RR data
+ rr_data_len = mdns_read_u16(p);
+ p += sizeof(uint16_t);
+
+ if (p + rr_data_len > e) {
+ DEBUG_PRINTF("rr_data_len goes beyond packet buffer: %lu > %lu\n", rr_data_len, e - p);
+ rr_entry_destroy(rr);
+ return 0;
+ }
+
+ e = p + rr_data_len;
+
+ // see if we can parse the RR data
+ switch (rr->type) {
+ case RR_A:
+ if (rr_data_len < sizeof(uint32_t)) {
+ DEBUG_PRINTF("invalid rr_data_len=%lu for A record\n", rr_data_len);
+ parse_error = 1;
+ break;
+ }
+ rr->data.A.addr = ntohl(mdns_read_u32(p)); /* addr already in net order */
+ p += sizeof(uint32_t);
+ break;
+
+ case RR_AAAA:
+ if (rr_data_len < sizeof(struct in6_addr)) {
+ DEBUG_PRINTF("invalid rr_data_len=%lu for AAAA record\n", rr_data_len);
+ parse_error = 1;
+ break;
+ }
+ rr->data.AAAA.addr = malloc(sizeof(struct in6_addr));
+ int i;
+ for (i = 0; i < sizeof(struct in6_addr); i++)
+ rr->data.AAAA.addr->s6_addr[i] = p[i];
+ p += sizeof(struct in6_addr);
+ break;
+
+ case RR_PTR:
+ rr->data.PTR.name = uncompress_nlabel(pkt_buf, pkt_len, p - pkt_buf);
+ if (rr->data.PTR.name == NULL) {
+ DEBUG_PRINTF("unable to parse/uncompress label for PTR name\n");
+ parse_error = 1;
+ break;
+ }
+ p += rr_data_len;
+ break;
+
+ case RR_TXT:
+ txt_rec = &rr->data.TXT;
+
+ // not supposed to happen, but we should handle it
+ if (rr_data_len == 0) {
+ DEBUG_PRINTF("WARN: rr_data_len for TXT is 0\n");
+ txt_rec->txt = create_label("");
+ break;
+ }
+
+ while (1) {
+ txt_rec->txt = copy_label(pkt_buf, pkt_len, p - pkt_buf);
+ if (txt_rec->txt == NULL) {
+ DEBUG_PRINTF("unable to copy label for TXT record\n");
+ parse_error = 1;
+ break;
+ }
+ p += txt_rec->txt[0] + 1;
+
+ if (p >= e)
+ break;
+
+ // allocate another record
+ txt_rec->next = malloc(sizeof(struct rr_data_txt));
+ txt_rec = txt_rec->next;
+ txt_rec->next = NULL;
+ }
+ break;
+
+ default:
+ // skip to end of RR data
+ p = e;
+ }
+
+ // if there was a parse error, destroy partial rr_entry
+ if (parse_error) {
+ rr_entry_destroy(rr);
+ return 0;
+ }
+
+ rr_list_append(&pkt->rr_ans, rr);
+
+ return p - (pkt_buf + off);
}
// parse a MDNS packet into an mdns_pkt struct
struct mdns_pkt *mdns_parse_pkt(uint8_t *pkt_buf, size_t pkt_len) {
- uint8_t *p = pkt_buf;
- size_t off;
- struct mdns_pkt *pkt;
- int i;
-
- if (pkt_len < 12)
- return NULL;
-
- MALLOC_ZERO_STRUCT(pkt, mdns_pkt);
-
- // parse header
- pkt->id = mdns_read_u16(p); p += sizeof(uint16_t);
- pkt->flags = mdns_read_u16(p); p += sizeof(uint16_t);
- pkt->num_qn = mdns_read_u16(p); p += sizeof(uint16_t);
- pkt->num_ans_rr = mdns_read_u16(p); p += sizeof(uint16_t);
- pkt->num_auth_rr = mdns_read_u16(p); p += sizeof(uint16_t);
- pkt->num_add_rr = mdns_read_u16(p); p += sizeof(uint16_t);
-
- off = p - pkt_buf;
-
- // parse questions
- for (i = 0; i < pkt->num_qn; i++) {
- size_t l = mdns_parse_qn(pkt_buf, pkt_len, off, pkt);
- if (! l) {
- DEBUG_PRINTF("error parsing question #%d\n", i);
- mdns_pkt_destroy(pkt);
- return NULL;
- }
-
- off += l;
+ uint8_t *p = pkt_buf;
+ size_t off;
+ struct mdns_pkt *pkt;
+ int i;
+
+ if (pkt_len < 12)
+ return NULL;
+
+ MALLOC_ZERO_STRUCT(pkt, mdns_pkt);
+
+ // parse header
+ pkt->id = mdns_read_u16(p);
+ p += sizeof(uint16_t);
+ pkt->flags = mdns_read_u16(p);
+ p += sizeof(uint16_t);
+ pkt->num_qn = mdns_read_u16(p);
+ p += sizeof(uint16_t);
+ pkt->num_ans_rr = mdns_read_u16(p);
+ p += sizeof(uint16_t);
+ pkt->num_auth_rr = mdns_read_u16(p);
+ p += sizeof(uint16_t);
+ pkt->num_add_rr = mdns_read_u16(p);
+ p += sizeof(uint16_t);
+
+ off = p - pkt_buf;
+
+ // parse questions
+ for (i = 0; i < pkt->num_qn; i++) {
+ size_t l = mdns_parse_qn(pkt_buf, pkt_len, off, pkt);
+ if (!l) {
+ DEBUG_PRINTF("error parsing question #%d\n", i);
+ mdns_pkt_destroy(pkt);
+ return NULL;
+ }
+
+ off += l;
+ }
+
+ // parse answer RRs
+ for (i = 0; i < pkt->num_ans_rr; i++) {
+ size_t l = mdns_parse_rr(pkt_buf, pkt_len, off, pkt);
+ if (!l) {
+ DEBUG_PRINTF("error parsing answer #%d\n", i);
+ mdns_pkt_destroy(pkt);
+ return NULL;
+ }
+
+ off += l;
+ }
+
+ // TODO: parse the authority and additional RR sections
+
+ return pkt;
+}
+
+// encodes a name (label) into a packet using the name compression scheme
+// encoded names will be added to the compression list for subsequent use
+static size_t mdns_encode_name(uint8_t *pkt_buf, size_t pkt_len, size_t off, const uint8_t *name,
+ struct name_comp *comp) {
+ struct name_comp *c, *c_tail = NULL;
+ uint8_t *p = pkt_buf + off;
+ size_t len = 0;
+
+ if (name) {
+ while (*name) {
+ // find match for compression
+ for (c = comp; c; c = c->next) {
+ if (cmp_nlabel(name, c->label) == 0) {
+ mdns_write_u16(p, 0xC000 | (c->pos & ~0xC000));
+ return len + sizeof(uint16_t);
}
- // parse answer RRs
- for (i = 0; i < pkt->num_ans_rr; i++) {
- size_t l = mdns_parse_rr(pkt_buf, pkt_len, off, pkt);
- if (! l) {
- DEBUG_PRINTF("error parsing answer #%d\n", i);
- mdns_pkt_destroy(pkt);
- return NULL;
- }
+ if (c->next == NULL)
+ c_tail = c;
+ }
- off += l;
- }
+ // copy this segment
+ int segment_len = *name + 1;
+ strncpy((char *)p, (char *)name, segment_len);
- // TODO: parse the authority and additional RR sections
+ // cache the name for subsequent compression
+ DECL_MALLOC_ZERO_STRUCT(new_c, name_comp);
- return pkt;
-}
+ new_c->label = (uint8_t *)name;
+ new_c->pos = p - pkt_buf;
+ c_tail->next = new_c;
-// encodes a name (label) into a packet using the name compression scheme
-// encoded names will be added to the compression list for subsequent use
-static size_t mdns_encode_name(uint8_t *pkt_buf, size_t pkt_len, size_t off,
- const uint8_t *name, struct name_comp *comp) {
- struct name_comp *c, *c_tail = NULL;
- uint8_t *p = pkt_buf + off;
- size_t len = 0;
-
- if (name) {
- while (*name) {
- // find match for compression
- for (c = comp; c; c = c->next) {
- if (cmp_nlabel(name, c->label) == 0) {
- mdns_write_u16(p, 0xC000 | (c->pos & ~0xC000));
- return len + sizeof(uint16_t);
- }
-
- if (c->next == NULL)
- c_tail = c;
- }
-
- // copy this segment
- int segment_len = *name + 1;
- strncpy((char *) p, (char *) name, segment_len);
-
- // cache the name for subsequent compression
- DECL_MALLOC_ZERO_STRUCT(new_c, name_comp);
-
- new_c->label = (uint8_t *) name;
- new_c->pos = p - pkt_buf;
- c_tail->next = new_c;
-
- // advance to next name segment
- p += segment_len;
- len += segment_len;
- name += segment_len;
- }
- }
+ // advance to next name segment
+ p += segment_len;
+ len += segment_len;
+ name += segment_len;
+ }
+ }
- *p = '\0'; // root "label"
- len += 1;
+ *p = '\0'; // root "label"
+ len += 1;
- return len;
+ return len;
}
// encodes an RR entry at the given offset
// returns the size of the entire RR entry
-static size_t mdns_encode_rr(uint8_t *pkt_buf, size_t pkt_len, size_t off,
- struct rr_entry *rr, struct name_comp *comp) {
- uint8_t *p = pkt_buf + off, *p_data;
- size_t l;
- struct rr_data_txt *txt_rec;
- uint8_t *label;
- int i;
+static size_t mdns_encode_rr(uint8_t *pkt_buf, size_t pkt_len, size_t off, struct rr_entry *rr,
+ struct name_comp *comp) {
+ uint8_t *p = pkt_buf + off, *p_data;
+ size_t l;
+ struct rr_data_txt *txt_rec;
+ uint8_t *label;
+ int i;
- assert(off < pkt_len);
+ assert(off < pkt_len);
- // name
- l = mdns_encode_name(pkt_buf, pkt_len, off, rr->name, comp);
- assert(l != 0);
- p += l;
+ // name
+ l = mdns_encode_name(pkt_buf, pkt_len, off, rr->name, comp);
+ assert(l != 0);
+ p += l;
- // type
- p = mdns_write_u16(p, rr->type);
+ // type
+ p = mdns_write_u16(p, rr->type);
- // class & cache flush
- p = mdns_write_u16(p, (rr->rr_class & ~0x8000) | (rr->cache_flush << 15));
+ // class & cache flush
+ p = mdns_write_u16(p, (rr->rr_class & ~0x8000) | (rr->cache_flush << 15));
- // TTL
- p = mdns_write_u32(p, rr->ttl);
+ // TTL
+ p = mdns_write_u32(p, rr->ttl);
- // data length (filled in later)
- p += sizeof(uint16_t);
+ // data length (filled in later)
+ p += sizeof(uint16_t);
- // start of data marker
- p_data = p;
+ // start of data marker
+ p_data = p;
- switch (rr->type) {
- case RR_A:
- /* htonl() needed coz addr already in net order */
- p = mdns_write_u32(p, htonl(rr->data.A.addr));
- break;
+ switch (rr->type) {
+ case RR_A:
+ /* htonl() needed coz addr already in net order */
+ p = mdns_write_u32(p, htonl(rr->data.A.addr));
+ break;
- case RR_AAAA:
- for (i = 0; i < sizeof(struct in6_addr); i++)
- *p++ = rr->data.AAAA.addr->s6_addr[i];
- break;
+ case RR_AAAA:
+ for (i = 0; i < sizeof(struct in6_addr); i++)
+ *p++ = rr->data.AAAA.addr->s6_addr[i];
+ break;
- case RR_PTR:
- label = rr->data.PTR.name ?
- rr->data.PTR.name :
- rr->data.PTR.entry->name;
- p += mdns_encode_name(pkt_buf, pkt_len, p - pkt_buf, label, comp);
- break;
+ case RR_PTR:
+ label = rr->data.PTR.name ? rr->data.PTR.name : rr->data.PTR.entry->name;
+ p += mdns_encode_name(pkt_buf, pkt_len, p - pkt_buf, label, comp);
+ break;
- case RR_TXT:
- txt_rec = &rr->data.TXT;
- for (; txt_rec; txt_rec = txt_rec->next) {
- int len = txt_rec->txt[0] + 1;
- strncpy((char *) p, (char *) txt_rec->txt, len);
- p += len;
- }
- break;
+ case RR_TXT:
+ txt_rec = &rr->data.TXT;
+ for (; txt_rec; txt_rec = txt_rec->next) {
+ int len = txt_rec->txt[0] + 1;
+ strncpy((char *)p, (char *)txt_rec->txt, len);
+ p += len;
+ }
+ break;
- case RR_SRV:
- p = mdns_write_u16(p, rr->data.SRV.priority);
+ case RR_SRV:
+ p = mdns_write_u16(p, rr->data.SRV.priority);
- p = mdns_write_u16(p, rr->data.SRV.weight);
+ p = mdns_write_u16(p, rr->data.SRV.weight);
- p = mdns_write_u16(p, rr->data.SRV.port);
+ p = mdns_write_u16(p, rr->data.SRV.port);
- p += mdns_encode_name(pkt_buf, pkt_len, p - pkt_buf,
- rr->data.SRV.target, comp);
- break;
+ p += mdns_encode_name(pkt_buf, pkt_len, p - pkt_buf, rr->data.SRV.target, comp);
+ break;
- case RR_NSEC:
- p += mdns_encode_name(pkt_buf, pkt_len, p - pkt_buf,
- rr->name, comp);
+ case RR_NSEC:
+ p += mdns_encode_name(pkt_buf, pkt_len, p - pkt_buf, rr->name, comp);
- *p++ = 0; // bitmap window/block number
+ *p++ = 0; // bitmap window/block number
- *p++ = sizeof(rr->data.NSEC.bitmap); // bitmap length
+ *p++ = sizeof(rr->data.NSEC.bitmap); // bitmap length
- for (i = 0; i < sizeof(rr->data.NSEC.bitmap); i++)
- *p++ = rr->data.NSEC.bitmap[i];
+ for (i = 0; i < sizeof(rr->data.NSEC.bitmap); i++)
+ *p++ = rr->data.NSEC.bitmap[i];
- break;
+ break;
- default:
- DEBUG_PRINTF("unhandled rr type 0x%02x\n", rr->type);
- }
+ default:
+ DEBUG_PRINTF("unhandled rr type 0x%02x\n", rr->type);
+ }
- // calculate data length based on p
- l = p - p_data;
+ // calculate data length based on p
+ l = p - p_data;
- // fill in the length
- mdns_write_u16(p - l - sizeof(uint16_t), l);
+ // fill in the length
+ mdns_write_u16(p - l - sizeof(uint16_t), l);
- return p - pkt_buf - off;
+ return p - pkt_buf - off;
}
// encodes a MDNS packet from the given mdns_pkt struct into a buffer
// returns the size of the entire MDNS packet
size_t mdns_encode_pkt(struct mdns_pkt *answer, uint8_t *pkt_buf, size_t pkt_len) {
- struct name_comp *comp;
- uint8_t *p = pkt_buf;
- //uint8_t *e = pkt_buf + pkt_len;
- size_t off;
- int i;
-
- assert(answer != NULL);
- assert(pkt_len >= 12);
-
- if (p == NULL)
- return -1;
-
- // this is an Answer - number of qns should be zero
- assert(answer->num_qn == 0);
-
- p = mdns_write_u16(p, answer->id);
- p = mdns_write_u16(p, answer->flags);
- p = mdns_write_u16(p, answer->num_qn);
- p = mdns_write_u16(p, answer->num_ans_rr);
- p = mdns_write_u16(p, answer->num_auth_rr);
- p = mdns_write_u16(p, answer->num_add_rr);
-
- off = p - pkt_buf;
-
- // allocate list for name compression
- comp = malloc(sizeof(struct name_comp));
- if (comp == NULL)
- return -1;
- memset(comp, 0, sizeof(struct name_comp));
-
- // dummy entry
- comp->label = (uint8_t *) "";
- comp->pos = 0;
-
- // skip encoding of qn
-
- struct rr_list *rr_set[] = {
- answer->rr_ans,
- answer->rr_auth,
- answer->rr_add
- };
-
- // encode answer, authority and additional RRs
- for (i = 0; i < sizeof(rr_set) / sizeof(rr_set[0]); i++) {
- struct rr_list *rr = rr_set[i];
- for (; rr; rr = rr->next) {
- size_t l = mdns_encode_rr(pkt_buf, pkt_len, off, rr->e, comp);
- off += l;
-
- if (off >= pkt_len) {
- DEBUG_PRINTF("packet buffer too small\n");
- return -1;
- }
- }
-
- }
-
- // free name compression list
- while (comp) {
- struct name_comp *c = comp->next;
- free(comp);
- comp = c;
- }
-
- return off;
+ struct name_comp *comp;
+ uint8_t *p = pkt_buf;
+ // uint8_t *e = pkt_buf + pkt_len;
+ size_t off;
+ int i;
+
+ assert(answer != NULL);
+ assert(pkt_len >= 12);
+
+ if (p == NULL)
+ return -1;
+
+ // this is an Answer - number of qns should be zero
+ assert(answer->num_qn == 0);
+
+ p = mdns_write_u16(p, answer->id);
+ p = mdns_write_u16(p, answer->flags);
+ p = mdns_write_u16(p, answer->num_qn);
+ p = mdns_write_u16(p, answer->num_ans_rr);
+ p = mdns_write_u16(p, answer->num_auth_rr);
+ p = mdns_write_u16(p, answer->num_add_rr);
+
+ off = p - pkt_buf;
+
+ // allocate list for name compression
+ comp = malloc(sizeof(struct name_comp));
+ if (comp == NULL)
+ return -1;
+ memset(comp, 0, sizeof(struct name_comp));
+
+ // dummy entry
+ comp->label = (uint8_t *)"";
+ comp->pos = 0;
+
+ // skip encoding of qn
+
+ struct rr_list *rr_set[] = {answer->rr_ans, answer->rr_auth, answer->rr_add};
+
+ // encode answer, authority and additional RRs
+ for (i = 0; i < sizeof(rr_set) / sizeof(rr_set[0]); i++) {
+ struct rr_list *rr = rr_set[i];
+ for (; rr; rr = rr->next) {
+ size_t l = mdns_encode_rr(pkt_buf, pkt_len, off, rr->e, comp);
+ off += l;
+
+ if (off >= pkt_len) {
+ DEBUG_PRINTF("packet buffer too small\n");
+ return -1;
+ }
+ }
+ }
+
+ // free name compression list
+ while (comp) {
+ struct name_comp *c = comp->next;
+ free(comp);
+ comp = c;
+ }
+
+ return off;
}
//******************************************************//
@@ -1064,621 +1063,599 @@ size_t mdns_encode_pkt(struct mdns_pkt *answer, uint8_t *pkt_buf, size_t pkt_len
#define PACKET_SIZE 65536
-#define SERVICES_DNS_SD_NLABEL \
- ((uint8_t *) "\x09_services\x07_dns-sd\x04_udp\x05local")
+#define SERVICES_DNS_SD_NLABEL ((uint8_t *)"\x09_services\x07_dns-sd\x04_udp\x05local")
struct mdnsd {
- pthread_mutex_t data_lock;
- int sockfd;
- int notify_pipe[2];
- int stop_flag;
-
- struct rr_group *group;
- struct rr_list *announce;
- struct rr_list *services;
- uint8_t *hostname;
+ pthread_mutex_t data_lock;
+ int sockfd;
+ int notify_pipe[2];
+ int stop_flag;
+
+ struct rr_group *group;
+ struct rr_list *announce;
+ struct rr_list *services;
+ uint8_t *hostname;
};
struct mdns_service {
- struct rr_list *entries;
+ struct rr_list *entries;
};
/////////////////////////////////
-
-
static int create_recv_sock() {
- int sd = socket(AF_INET, SOCK_DGRAM, 0);
- if (sd < 0) {
- log_message(LOG_ERR, "recv socket(): %m");
- return sd;
- }
-
- int r = -1;
-
- int on = 1;
- if ((r = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on))) < 0) {
- log_message(LOG_ERR, "recv setsockopt(SO_REUSEADDR): %m");
- return r;
- }
-
- /* bind to an address */
- struct sockaddr_in serveraddr;
- memset(&serveraddr, 0, sizeof(serveraddr));
- serveraddr.sin_family = AF_INET;
- serveraddr.sin_port = htons(MDNS_PORT);
- serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); /* receive multicast */
- if ((r = bind(sd, (struct sockaddr *)&serveraddr, sizeof(serveraddr))) < 0) {
- log_message(LOG_ERR, "recv bind(): %m");
- }
-
- // add membership to receiving socket
- struct ip_mreq mreq;
- memset(&mreq, 0, sizeof(struct ip_mreq));
- mreq.imr_interface.s_addr = htonl(INADDR_ANY);
- mreq.imr_multiaddr.s_addr = inet_addr(MDNS_ADDR);
- if ((r = setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq))) < 0) {
- log_message(LOG_ERR, "recv setsockopt(IP_ADD_MEMBERSHIP): %m");
- return r;
- }
-
- // enable loopback in case someone else needs the data
- if ((r = setsockopt(sd, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &on, sizeof(on))) < 0) {
- log_message(LOG_ERR, "recv setsockopt(IP_MULTICAST_LOOP): %m");
- return r;
- }
-
+ int sd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sd < 0) {
+ log_message(LOG_ERR, "recv socket(): %m");
+ return sd;
+ }
+
+ int r = -1;
+
+ int on = 1;
+ if ((r = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on))) < 0) {
+ log_message(LOG_ERR, "recv setsockopt(SO_REUSEADDR): %m");
+ return r;
+ }
+
+ /* bind to an address */
+ struct sockaddr_in serveraddr;
+ memset(&serveraddr, 0, sizeof(serveraddr));
+ serveraddr.sin_family = AF_INET;
+ serveraddr.sin_port = htons(MDNS_PORT);
+ serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); /* receive multicast */
+ if ((r = bind(sd, (struct sockaddr *)&serveraddr, sizeof(serveraddr))) < 0) {
+ log_message(LOG_ERR, "recv bind(): %m");
+ }
+
+ // add membership to receiving socket
+ struct ip_mreq mreq;
+ memset(&mreq, 0, sizeof(struct ip_mreq));
+ mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+ mreq.imr_multiaddr.s_addr = inet_addr(MDNS_ADDR);
+ if ((r = setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq))) < 0) {
+ log_message(LOG_ERR, "recv setsockopt(IP_ADD_MEMBERSHIP): %m");
+ return r;
+ }
+
+ // enable loopback in case someone else needs the data
+ if ((r = setsockopt(sd, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&on, sizeof(on))) < 0) {
+ log_message(LOG_ERR, "recv setsockopt(IP_MULTICAST_LOOP): %m");
+ return r;
+ }
#ifdef IP_PKTINFO
- if ((r = setsockopt(sd, SOL_IP, IP_PKTINFO, (char *) &on, sizeof(on))) < 0) {
- log_message(LOG_ERR, "recv setsockopt(IP_PKTINFO): %m");
- return r;
- }
+ if ((r = setsockopt(sd, SOL_IP, IP_PKTINFO, (char *)&on, sizeof(on))) < 0) {
+ log_message(LOG_ERR, "recv setsockopt(IP_PKTINFO): %m");
+ return r;
+ }
#endif
- return sd;
+ return sd;
}
static ssize_t send_packet(int fd, const void *data, size_t len) {
- static struct sockaddr_in toaddr;
- if (toaddr.sin_family != AF_INET) {
- memset(&toaddr, 0, sizeof(struct sockaddr_in));
- toaddr.sin_family = AF_INET;
- toaddr.sin_port = htons(MDNS_PORT);
- toaddr.sin_addr.s_addr = inet_addr(MDNS_ADDR);
- }
-
- return sendto(fd, data, len, 0, (struct sockaddr *) &toaddr, sizeof(struct sockaddr_in));
+ static struct sockaddr_in toaddr;
+ if (toaddr.sin_family != AF_INET) {
+ memset(&toaddr, 0, sizeof(struct sockaddr_in));
+ toaddr.sin_family = AF_INET;
+ toaddr.sin_port = htons(MDNS_PORT);
+ toaddr.sin_addr.s_addr = inet_addr(MDNS_ADDR);
+ }
+
+ return sendto(fd, data, len, 0, (struct sockaddr *)&toaddr, sizeof(struct sockaddr_in));
}
-
// populate the specified list which matches the RR name and type
// type can be RR_ANY, which populates all entries EXCEPT RR_NSEC
-static int populate_answers(struct mdnsd *svr, struct rr_list **rr_head, uint8_t *name, enum rr_type type) {
- int num_ans = 0;
-
- // check if we have the records
- pthread_mutex_lock(&svr->data_lock);
- struct rr_group *ans_grp = rr_group_find(svr->group, name);
- if (ans_grp == NULL) {
- pthread_mutex_unlock(&svr->data_lock);
- return num_ans;
- }
-
- // decide which records should go into answers
- struct rr_list *n = ans_grp->rr;
- for (; n; n = n->next) {
- // exclude NSEC for RR_ANY
- if (type == RR_ANY && n->e->type == RR_NSEC)
- continue;
-
- if ((type == n->e->type || type == RR_ANY) && cmp_nlabel(name, n->e->name) == 0) {
- num_ans += rr_list_append(rr_head, n->e);
- }
- }
-
- pthread_mutex_unlock(&svr->data_lock);
-
- return num_ans;
+static int populate_answers(struct mdnsd *svr, struct rr_list **rr_head, uint8_t *name,
+ enum rr_type type) {
+ int num_ans = 0;
+
+ // check if we have the records
+ pthread_mutex_lock(&svr->data_lock);
+ struct rr_group *ans_grp = rr_group_find(svr->group, name);
+ if (ans_grp == NULL) {
+ pthread_mutex_unlock(&svr->data_lock);
+ return num_ans;
+ }
+
+ // decide which records should go into answers
+ struct rr_list *n = ans_grp->rr;
+ for (; n; n = n->next) {
+ // exclude NSEC for RR_ANY
+ if (type == RR_ANY && n->e->type == RR_NSEC)
+ continue;
+
+ if ((type == n->e->type || type == RR_ANY) && cmp_nlabel(name, n->e->name) == 0) {
+ num_ans += rr_list_append(rr_head, n->e);
+ }
+ }
+
+ pthread_mutex_unlock(&svr->data_lock);
+
+ return num_ans;
}
// given a list of RRs, look up related records and add them
static void add_related_rr(struct mdnsd *svr, struct rr_list *list, struct mdns_pkt *reply) {
- for (; list; list = list->next) {
- struct rr_entry *ans = list->e;
-
- switch (ans->type) {
- case RR_PTR:
- // target host A, AAAA records
- reply->num_add_rr += populate_answers(svr, &reply->rr_add,
- MDNS_RR_GET_PTR_NAME(ans), RR_ANY);
- break;
-
- case RR_SRV:
- // target host A, AAAA records
- reply->num_add_rr += populate_answers(svr, &reply->rr_add,
- ans->data.SRV.target, RR_ANY);
-
- // perhaps TXT records of the same name?
- // if we use RR_ANY, we risk pulling in the same RR_SRV
- reply->num_add_rr += populate_answers(svr, &reply->rr_add,
- ans->name, RR_TXT);
- break;
-
- case RR_A:
- case RR_AAAA:
- reply->num_add_rr += populate_answers(svr, &reply->rr_add,
- ans->name, RR_NSEC);
- break;
-
- default:
- // nothing to add
- break;
- }
- }
+ for (; list; list = list->next) {
+ struct rr_entry *ans = list->e;
+
+ switch (ans->type) {
+ case RR_PTR:
+ // target host A, AAAA records
+ reply->num_add_rr += populate_answers(svr, &reply->rr_add, MDNS_RR_GET_PTR_NAME(ans), RR_ANY);
+ break;
+
+ case RR_SRV:
+ // target host A, AAAA records
+ reply->num_add_rr += populate_answers(svr, &reply->rr_add, ans->data.SRV.target, RR_ANY);
+
+ // perhaps TXT records of the same name?
+ // if we use RR_ANY, we risk pulling in the same RR_SRV
+ reply->num_add_rr += populate_answers(svr, &reply->rr_add, ans->name, RR_TXT);
+ break;
+
+ case RR_A:
+ case RR_AAAA:
+ reply->num_add_rr += populate_answers(svr, &reply->rr_add, ans->name, RR_NSEC);
+ break;
+
+ default:
+ // nothing to add
+ break;
+ }
+ }
}
// creates an announce packet given the type name PTR
static void announce_srv(struct mdnsd *svr, struct mdns_pkt *reply, uint8_t *name) {
- mdns_init_reply(reply, 0);
+ mdns_init_reply(reply, 0);
- reply->num_ans_rr += populate_answers(svr, &reply->rr_ans, name, RR_PTR);
+ reply->num_ans_rr += populate_answers(svr, &reply->rr_ans, name, RR_PTR);
- // remember to add the services dns-sd PTR too
- reply->num_ans_rr += populate_answers(svr, &reply->rr_ans,
- SERVICES_DNS_SD_NLABEL, RR_PTR);
+ // remember to add the services dns-sd PTR too
+ reply->num_ans_rr += populate_answers(svr, &reply->rr_ans, SERVICES_DNS_SD_NLABEL, RR_PTR);
- // see if we can match additional records for answers
- add_related_rr(svr, reply->rr_ans, reply);
+ // see if we can match additional records for answers
+ add_related_rr(svr, reply->rr_ans, reply);
- // additional records for additional records
- add_related_rr(svr, reply->rr_add, reply);
+ // additional records for additional records
+ add_related_rr(svr, reply->rr_add, reply);
}
// processes the incoming MDNS packet
// returns >0 if processed, 0 otherwise
static int process_mdns_pkt(struct mdnsd *svr, struct mdns_pkt *pkt, struct mdns_pkt *reply) {
- int i;
-
- assert(pkt != NULL);
+ int i;
- // is it standard query?
- if ((pkt->flags & MDNS_FLAG_RESP) == 0 &&
- MDNS_FLAG_GET_OPCODE(pkt->flags) == 0) {
- mdns_init_reply(reply, pkt->id);
+ assert(pkt != NULL);
- DEBUG_PRINTF("flags = %04x, qn = %d, ans = %d, add = %d\n",
- pkt->flags,
- pkt->num_qn,
- pkt->num_ans_rr,
- pkt->num_add_rr);
+ // is it standard query?
+ if ((pkt->flags & MDNS_FLAG_RESP) == 0 && MDNS_FLAG_GET_OPCODE(pkt->flags) == 0) {
+ mdns_init_reply(reply, pkt->id);
- // loop through questions
- struct rr_list *qnl = pkt->rr_qn;
- for (i = 0; i < pkt->num_qn; i++, qnl = qnl->next) {
- struct rr_entry *qn = qnl->e;
- int num_ans_added = 0;
+ DEBUG_PRINTF("flags = %04x, qn = %d, ans = %d, add = %d\n", pkt->flags, pkt->num_qn,
+ pkt->num_ans_rr, pkt->num_add_rr);
- char *namestr = nlabel_to_str(qn->name);
- DEBUG_PRINTF("qn #%d: type %s (%02x) %s - ", i, rr_get_type_name(qn->type), qn->type, namestr);
- free(namestr);
+ // loop through questions
+ struct rr_list *qnl = pkt->rr_qn;
+ for (i = 0; i < pkt->num_qn; i++, qnl = qnl->next) {
+ struct rr_entry *qn = qnl->e;
+ int num_ans_added = 0;
- // check if it's a unicast query - we ignore those
- if (qn->unicast_query) {
- DEBUG_PRINTF("skipping unicast query\n");
- continue;
- }
+ char *namestr = nlabel_to_str(qn->name);
+ DEBUG_PRINTF("qn #%d: type %s (%02x) %s - ", i, rr_get_type_name(qn->type), qn->type,
+ namestr);
+ free(namestr);
- num_ans_added = populate_answers(svr, &reply->rr_ans, qn->name, qn->type);
- reply->num_ans_rr += num_ans_added;
+ // check if it's a unicast query - we ignore those
+ if (qn->unicast_query) {
+ DEBUG_PRINTF("skipping unicast query\n");
+ continue;
+ }
- DEBUG_PRINTF("added %d answers\n", num_ans_added);
- }
+ num_ans_added = populate_answers(svr, &reply->rr_ans, qn->name, qn->type);
+ reply->num_ans_rr += num_ans_added;
- // remove our replies if they were already in their answers
- struct rr_list *ans = NULL, *prev_ans = NULL;
- for (ans = reply->rr_ans; ans; ) {
- struct rr_list *next_ans = ans->next;
- struct rr_entry *known_ans = rr_entry_match(pkt->rr_ans, ans->e);
+ DEBUG_PRINTF("added %d answers\n", num_ans_added);
+ }
- // discard answers that have at least half of the actual TTL
- if (known_ans != NULL && known_ans->ttl >= ans->e->ttl / 2) {
- char *namestr = nlabel_to_str(ans->e->name);
- DEBUG_PRINTF("removing answer for %s\n", namestr);
- free(namestr);
+ // remove our replies if they were already in their answers
+ struct rr_list *ans = NULL, *prev_ans = NULL;
+ for (ans = reply->rr_ans; ans;) {
+ struct rr_list *next_ans = ans->next;
+ struct rr_entry *known_ans = rr_entry_match(pkt->rr_ans, ans->e);
- // check if list item is head
- if (prev_ans == NULL)
- reply->rr_ans = ans->next;
- else
- prev_ans->next = ans->next;
- free(ans);
+ // discard answers that have at least half of the actual TTL
+ if (known_ans != NULL && known_ans->ttl >= ans->e->ttl / 2) {
+ char *namestr = nlabel_to_str(ans->e->name);
+ DEBUG_PRINTF("removing answer for %s\n", namestr);
+ free(namestr);
- ans = prev_ans;
+ // check if list item is head
+ if (prev_ans == NULL)
+ reply->rr_ans = ans->next;
+ else
+ prev_ans->next = ans->next;
+ free(ans);
- // adjust answer count
- reply->num_ans_rr--;
- }
+ ans = prev_ans;
- prev_ans = ans;
- ans = next_ans;
- }
+ // adjust answer count
+ reply->num_ans_rr--;
+ }
+ prev_ans = ans;
+ ans = next_ans;
+ }
- // see if we can match additional records for answers
- add_related_rr(svr, reply->rr_ans, reply);
+ // see if we can match additional records for answers
+ add_related_rr(svr, reply->rr_ans, reply);
- // additional records for additional records
- add_related_rr(svr, reply->rr_add, reply);
+ // additional records for additional records
+ add_related_rr(svr, reply->rr_add, reply);
- DEBUG_PRINTF("\n");
+ DEBUG_PRINTF("\n");
- return reply->num_ans_rr;
- }
+ return reply->num_ans_rr;
+ }
- return 0;
+ return 0;
}
int create_pipe(int handles[2]) {
#ifdef _WIN32
- SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
- if (sock == INVALID_SOCKET) {
- return -1;
- }
- struct sockaddr_in serv_addr;
- memset(&serv_addr, 0, sizeof(serv_addr));
- serv_addr.sin_family = AF_INET;
- serv_addr.sin_port = htons(0);
- serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- if (bind(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == SOCKET_ERROR) {
- closesocket(sock);
- return -1;
- }
- if (listen(sock, 1) == SOCKET_ERROR) {
- closesocket(sock);
- return -1;
- }
- int len = sizeof(serv_addr);
- if (getsockname(sock, (SOCKADDR*)&serv_addr, &len) == SOCKET_ERROR) {
- closesocket(sock);
- return -1;
- }
- if ((handles[1] = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
- closesocket(sock);
- return -1;
- }
- if (connect(handles[1], (struct sockaddr*)&serv_addr, len) == SOCKET_ERROR) {
- closesocket(sock);
- return -1;
- }
- if ((handles[0] = accept(sock, (struct sockaddr*)&serv_addr, &len)) == INVALID_SOCKET) {
- closesocket((SOCKET)handles[1]);
- handles[1] = INVALID_SOCKET;
- closesocket(sock);
- return -1;
- }
- closesocket(sock);
- return 0;
+ SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (sock == INVALID_SOCKET) {
+ return -1;
+ }
+ struct sockaddr_in serv_addr;
+ memset(&serv_addr, 0, sizeof(serv_addr));
+ serv_addr.sin_family = AF_INET;
+ serv_addr.sin_port = htons(0);
+ serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ if (bind(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == SOCKET_ERROR) {
+ closesocket(sock);
+ return -1;
+ }
+ if (listen(sock, 1) == SOCKET_ERROR) {
+ closesocket(sock);
+ return -1;
+ }
+ int len = sizeof(serv_addr);
+ if (getsockname(sock, (SOCKADDR *)&serv_addr, &len) == SOCKET_ERROR) {
+ closesocket(sock);
+ return -1;
+ }
+ if ((handles[1] = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
+ closesocket(sock);
+ return -1;
+ }
+ if (connect(handles[1], (struct sockaddr *)&serv_addr, len) == SOCKET_ERROR) {
+ closesocket(sock);
+ return -1;
+ }
+ if ((handles[0] = accept(sock, (struct sockaddr *)&serv_addr, &len)) == INVALID_SOCKET) {
+ closesocket((SOCKET)handles[1]);
+ handles[1] = INVALID_SOCKET;
+ closesocket(sock);
+ return -1;
+ }
+ closesocket(sock);
+ return 0;
#else
- return pipe(handles);
+ return pipe(handles);
#endif
}
-int read_pipe(int s, char* buf, int len) {
+int read_pipe(int s, char *buf, int len) {
#ifdef _WIN32
- int ret = recv(s, buf, len, 0);
- if (ret < 0 && WSAGetLastError() == WSAECONNRESET) {
- ret = 0;
- }
- return ret;
+ int ret = recv(s, buf, len, 0);
+ if (ret < 0 && WSAGetLastError() == WSAECONNRESET) {
+ ret = 0;
+ }
+ return ret;
#else
- return read(s, buf, len);
+ return read(s, buf, len);
#endif
}
-int write_pipe(int s, char* buf, int len) {
+int write_pipe(int s, char *buf, int len) {
#ifdef _WIN32
- return send(s, buf, len, 0);
+ return send(s, buf, len, 0);
#else
- return write(s, buf, len);
+ return write(s, buf, len);
#endif
}
int close_pipe(int s) {
#ifdef _WIN32
- return closesocket(s);
+ return closesocket(s);
#else
- return close(s);
+ return close(s);
#endif
}
// main loop to receive, process and send out MDNS replies
// also handles MDNS service announces
static void main_loop(struct mdnsd *svr) {
- fd_set sockfd_set;
- int max_fd = svr->sockfd;
- char notify_buf[2]; // buffer for reading of notify_pipe
-
- void *pkt_buffer = malloc(PACKET_SIZE);
-
- if (svr->notify_pipe[0] > max_fd)
- max_fd = svr->notify_pipe[0];
-
- struct mdns_pkt *mdns_reply = malloc(sizeof(struct mdns_pkt));
- memset(mdns_reply, 0, sizeof(struct mdns_pkt));
-
- while (! svr->stop_flag) {
- FD_ZERO(&sockfd_set);
- FD_SET(svr->sockfd, &sockfd_set);
- FD_SET(svr->notify_pipe[0], &sockfd_set);
- select(max_fd + 1, &sockfd_set, NULL, NULL, NULL);
-
- if (FD_ISSET(svr->notify_pipe[0], &sockfd_set)) {
- // flush the notify_pipe
- read_pipe(svr->notify_pipe[0], (char*)&notify_buf, 1);
- } else if (FD_ISSET(svr->sockfd, &sockfd_set)) {
- struct sockaddr_in fromaddr;
- socklen_t sockaddr_size = sizeof(struct sockaddr_in);
-
- ssize_t recvsize = recvfrom(svr->sockfd, pkt_buffer, PACKET_SIZE, 0,
- (struct sockaddr *) &fromaddr, &sockaddr_size);
- if (recvsize < 0) {
- log_message(LOG_ERR, "recv(): %m");
- }
-
- DEBUG_PRINTF("data from=%s size=%ld\n", inet_ntoa(fromaddr.sin_addr), (long) recvsize);
- struct mdns_pkt *mdns = mdns_parse_pkt(pkt_buffer, recvsize);
- if (mdns != NULL) {
- if (process_mdns_pkt(svr, mdns, mdns_reply)) {
- size_t replylen = mdns_encode_pkt(mdns_reply, pkt_buffer, PACKET_SIZE);
- send_packet(svr->sockfd, pkt_buffer, replylen);
- } else if (mdns->num_qn == 0) {
- DEBUG_PRINTF("(no questions in packet)\n\n");
- }
-
- mdns_pkt_destroy(mdns);
- }
- }
-
- // send out announces
- while (1) {
- struct rr_entry *ann_e = NULL;
-
- // extract from head of list
- pthread_mutex_lock(&svr->data_lock);
- if (svr->announce)
- ann_e = rr_list_remove(&svr->announce, svr->announce->e);
- pthread_mutex_unlock(&svr->data_lock);
-
- if (! ann_e)
- break;
-
- char *namestr = nlabel_to_str(ann_e->name);
- DEBUG_PRINTF("sending announce for %s\n", namestr);
- free(namestr);
-
- announce_srv(svr, mdns_reply, ann_e->name);
-
- if (mdns_reply->num_ans_rr > 0) {
- size_t replylen = mdns_encode_pkt(mdns_reply, pkt_buffer, PACKET_SIZE);
- send_packet(svr->sockfd, pkt_buffer, replylen);
- }
- }
+ fd_set sockfd_set;
+ int max_fd = svr->sockfd;
+ char notify_buf[2]; // buffer for reading of notify_pipe
+
+ void *pkt_buffer = malloc(PACKET_SIZE);
+
+ if (svr->notify_pipe[0] > max_fd)
+ max_fd = svr->notify_pipe[0];
+
+ struct mdns_pkt *mdns_reply = malloc(sizeof(struct mdns_pkt));
+ memset(mdns_reply, 0, sizeof(struct mdns_pkt));
+
+ while (!svr->stop_flag) {
+ FD_ZERO(&sockfd_set);
+ FD_SET(svr->sockfd, &sockfd_set);
+ FD_SET(svr->notify_pipe[0], &sockfd_set);
+ select(max_fd + 1, &sockfd_set, NULL, NULL, NULL);
+
+ if (FD_ISSET(svr->notify_pipe[0], &sockfd_set)) {
+ // flush the notify_pipe
+ read_pipe(svr->notify_pipe[0], (char *)&notify_buf, 1);
+ } else if (FD_ISSET(svr->sockfd, &sockfd_set)) {
+ struct sockaddr_in fromaddr;
+ socklen_t sockaddr_size = sizeof(struct sockaddr_in);
+
+ ssize_t recvsize = recvfrom(svr->sockfd, pkt_buffer, PACKET_SIZE, 0,
+ (struct sockaddr *)&fromaddr, &sockaddr_size);
+ if (recvsize < 0) {
+ log_message(LOG_ERR, "recv(): %m");
+ }
+
+ DEBUG_PRINTF("data from=%s size=%ld\n", inet_ntoa(fromaddr.sin_addr), (long)recvsize);
+ struct mdns_pkt *mdns = mdns_parse_pkt(pkt_buffer, recvsize);
+ if (mdns != NULL) {
+ if (process_mdns_pkt(svr, mdns, mdns_reply)) {
+ size_t replylen = mdns_encode_pkt(mdns_reply, pkt_buffer, PACKET_SIZE);
+ send_packet(svr->sockfd, pkt_buffer, replylen);
+ } else if (mdns->num_qn == 0) {
+ DEBUG_PRINTF("(no questions in packet)\n\n");
}
- // main thread terminating. send out "goodbye packets" for services
- mdns_init_reply(mdns_reply, 0);
+ mdns_pkt_destroy(mdns);
+ }
+ }
- pthread_mutex_lock(&svr->data_lock);
- struct rr_list *svc_le = svr->services;
- for (; svc_le; svc_le = svc_le->next) {
- // set TTL to zero
- svc_le->e->ttl = 0;
- mdns_reply->num_ans_rr += rr_list_append(&mdns_reply->rr_ans, svc_le->e);
- }
- pthread_mutex_unlock(&svr->data_lock);
+ // send out announces
+ while (1) {
+ struct rr_entry *ann_e = NULL;
- // send out packet
- if (mdns_reply->num_ans_rr > 0) {
- size_t replylen = mdns_encode_pkt(mdns_reply, pkt_buffer, PACKET_SIZE);
- send_packet(svr->sockfd, pkt_buffer, replylen);
- }
+ // extract from head of list
+ pthread_mutex_lock(&svr->data_lock);
+ if (svr->announce)
+ ann_e = rr_list_remove(&svr->announce, svr->announce->e);
+ pthread_mutex_unlock(&svr->data_lock);
- // destroy packet
- mdns_init_reply(mdns_reply, 0);
- free(mdns_reply);
+ if (!ann_e)
+ break;
- free(pkt_buffer);
+ char *namestr = nlabel_to_str(ann_e->name);
+ DEBUG_PRINTF("sending announce for %s\n", namestr);
+ free(namestr);
- close_pipe(svr->sockfd);
+ announce_srv(svr, mdns_reply, ann_e->name);
- svr->stop_flag = 2;
-}
+ if (mdns_reply->num_ans_rr > 0) {
+ size_t replylen = mdns_encode_pkt(mdns_reply, pkt_buffer, PACKET_SIZE);
+ send_packet(svr->sockfd, pkt_buffer, replylen);
+ }
+ }
+ }
-/////////////////////////////////////////////////////
+ // main thread terminating. send out "goodbye packets" for services
+ mdns_init_reply(mdns_reply, 0);
+ pthread_mutex_lock(&svr->data_lock);
+ struct rr_list *svc_le = svr->services;
+ for (; svc_le; svc_le = svc_le->next) {
+ // set TTL to zero
+ svc_le->e->ttl = 0;
+ mdns_reply->num_ans_rr += rr_list_append(&mdns_reply->rr_ans, svc_le->e);
+ }
+ pthread_mutex_unlock(&svr->data_lock);
-void mdnsd_set_hostname(struct mdnsd *svr, const char *hostname, uint32_t ip) {
- struct rr_entry *a_e = NULL,
- *nsec_e = NULL;
+ // send out packet
+ if (mdns_reply->num_ans_rr > 0) {
+ size_t replylen = mdns_encode_pkt(mdns_reply, pkt_buffer, PACKET_SIZE);
+ send_packet(svr->sockfd, pkt_buffer, replylen);
+ }
- // currently can't be called twice
- // dont ask me what happens if the IP changes
- assert(svr->hostname == NULL);
+ // destroy packet
+ mdns_init_reply(mdns_reply, 0);
+ free(mdns_reply);
- a_e = rr_create_a(create_nlabel(hostname), ip); // 120 seconds automatically
+ free(pkt_buffer);
- nsec_e = rr_create(create_nlabel(hostname), RR_NSEC);
- nsec_e->ttl = DEFAULT_TTL_FOR_RECORD_WITH_HOSTNAME; // set to 120 seconds (default is 4500)
- rr_set_nsec(nsec_e, RR_A);
+ close_pipe(svr->sockfd);
- pthread_mutex_lock(&svr->data_lock);
- svr->hostname = create_nlabel(hostname);
- rr_group_add(&svr->group, a_e);
- rr_group_add(&svr->group, nsec_e);
- pthread_mutex_unlock(&svr->data_lock);
+ svr->stop_flag = 2;
}
-void mdnsd_set_hostname_v6(struct mdnsd *svr, const char *hostname, struct in6_addr *addr)
-{
- struct rr_entry *aaaa_e = NULL,
- *nsec_e = NULL;
+/////////////////////////////////////////////////////
- // currently can't be called twice
- // dont ask me what happens if the IP changes
- assert(svr->hostname == NULL);
+void mdnsd_set_hostname(struct mdnsd *svr, const char *hostname, uint32_t ip) {
+ struct rr_entry *a_e = NULL, *nsec_e = NULL;
- aaaa_e = rr_create_aaaa(create_nlabel(hostname), addr); // 120 seconds automatically
+ // currently can't be called twice
+ // dont ask me what happens if the IP changes
+ assert(svr->hostname == NULL);
- nsec_e = rr_create(create_nlabel(hostname), RR_NSEC);
- nsec_e->ttl = DEFAULT_TTL_FOR_RECORD_WITH_HOSTNAME; // set to 120 seconds (default is 4500)
- rr_set_nsec(nsec_e, RR_AAAA);
+ a_e = rr_create_a(create_nlabel(hostname), ip); // 120 seconds automatically
- pthread_mutex_lock(&svr->data_lock);
- svr->hostname = create_nlabel(hostname);
- rr_group_add(&svr->group, aaaa_e);
- rr_group_add(&svr->group, nsec_e);
- pthread_mutex_unlock(&svr->data_lock);
-}
+ nsec_e = rr_create(create_nlabel(hostname), RR_NSEC);
+ nsec_e->ttl = DEFAULT_TTL_FOR_RECORD_WITH_HOSTNAME; // set to 120 seconds (default is 4500)
+ rr_set_nsec(nsec_e, RR_A);
-void mdnsd_add_rr(struct mdnsd *svr, struct rr_entry *rr) {
- pthread_mutex_lock(&svr->data_lock);
- rr_group_add(&svr->group, rr);
- pthread_mutex_unlock(&svr->data_lock);
+ pthread_mutex_lock(&svr->data_lock);
+ svr->hostname = create_nlabel(hostname);
+ rr_group_add(&svr->group, a_e);
+ rr_group_add(&svr->group, nsec_e);
+ pthread_mutex_unlock(&svr->data_lock);
}
-struct mdns_service *mdnsd_register_svc(struct mdnsd *svr, const char *instance_name,
- const char *type, uint16_t port, const char *hostname, const char *txt[]) {
- struct rr_entry *txt_e = NULL,
- *srv_e = NULL,
- *ptr_e = NULL,
- *bptr_e = NULL;
- uint8_t *target;
- uint8_t *inst_nlabel, *type_nlabel, *nlabel;
- struct mdns_service *service = malloc(sizeof(struct mdns_service));
- memset(service, 0, sizeof(struct mdns_service));
-
- // combine service name
- type_nlabel = create_nlabel(type);
- inst_nlabel = create_label(instance_name);
- nlabel = join_nlabel(inst_nlabel, type_nlabel);
-
- // create TXT record
- if (txt && *txt) {
- txt_e = rr_create(dup_nlabel(nlabel), RR_TXT); // automatically 4500 seconds
- rr_list_append(&service->entries, txt_e);
-
- // add TXTs
- for (; *txt; txt++)
- rr_add_txt(txt_e, *txt);
- }
-
- // create SRV record
- assert(hostname || svr->hostname); // either one as target
- target = hostname ?
- create_nlabel(hostname) :
- dup_nlabel(svr->hostname);
-
- srv_e = rr_create_srv(dup_nlabel(nlabel), port, target); // automatically 4500 seconds
- rr_list_append(&service->entries, srv_e);
-
- // create PTR record for type
- ptr_e = rr_create_ptr(type_nlabel, srv_e); // automatically 4500 seconds
-
- // create services PTR record for type
- // this enables the type to show up as a "service"
- bptr_e = rr_create_ptr(dup_nlabel(SERVICES_DNS_SD_NLABEL), ptr_e); // automatically 4500 seconds
+void mdnsd_set_hostname_v6(struct mdnsd *svr, const char *hostname, struct in6_addr *addr) {
+ struct rr_entry *aaaa_e = NULL, *nsec_e = NULL;
- // modify lists here
- pthread_mutex_lock(&svr->data_lock);
+ // currently can't be called twice
+ // dont ask me what happens if the IP changes
+ assert(svr->hostname == NULL);
- if (txt_e)
- rr_group_add(&svr->group, txt_e);
- rr_group_add(&svr->group, srv_e);
- rr_group_add(&svr->group, ptr_e);
- rr_group_add(&svr->group, bptr_e);
+ aaaa_e = rr_create_aaaa(create_nlabel(hostname), addr); // 120 seconds automatically
- // append PTR entry to announce list
- rr_list_append(&svr->announce, ptr_e);
- rr_list_append(&svr->services, ptr_e);
+ nsec_e = rr_create(create_nlabel(hostname), RR_NSEC);
+ nsec_e->ttl = DEFAULT_TTL_FOR_RECORD_WITH_HOSTNAME; // set to 120 seconds (default is 4500)
+ rr_set_nsec(nsec_e, RR_AAAA);
- pthread_mutex_unlock(&svr->data_lock);
-
- // don't free type_nlabel - it's with the PTR record
- free(nlabel);
- free(inst_nlabel);
+ pthread_mutex_lock(&svr->data_lock);
+ svr->hostname = create_nlabel(hostname);
+ rr_group_add(&svr->group, aaaa_e);
+ rr_group_add(&svr->group, nsec_e);
+ pthread_mutex_unlock(&svr->data_lock);
+}
- // notify server
- write_pipe(svr->notify_pipe[1], ".", 1);
+void mdnsd_add_rr(struct mdnsd *svr, struct rr_entry *rr) {
+ pthread_mutex_lock(&svr->data_lock);
+ rr_group_add(&svr->group, rr);
+ pthread_mutex_unlock(&svr->data_lock);
+}
- return service;
+struct mdns_service *mdnsd_register_svc(struct mdnsd *svr, const char *instance_name,
+ const char *type, uint16_t port, const char *hostname,
+ const char *txt[]) {
+ struct rr_entry *txt_e = NULL, *srv_e = NULL, *ptr_e = NULL, *bptr_e = NULL;
+ uint8_t *target;
+ uint8_t *inst_nlabel, *type_nlabel, *nlabel;
+ struct mdns_service *service = malloc(sizeof(struct mdns_service));
+ memset(service, 0, sizeof(struct mdns_service));
+
+ // combine service name
+ type_nlabel = create_nlabel(type);
+ inst_nlabel = create_label(instance_name);
+ nlabel = join_nlabel(inst_nlabel, type_nlabel);
+
+ // create TXT record
+ if (txt && *txt) {
+ txt_e = rr_create(dup_nlabel(nlabel), RR_TXT); // automatically 4500 seconds
+ rr_list_append(&service->entries, txt_e);
+
+ // add TXTs
+ for (; *txt; txt++)
+ rr_add_txt(txt_e, *txt);
+ }
+
+ // create SRV record
+ assert(hostname || svr->hostname); // either one as target
+ target = hostname ? create_nlabel(hostname) : dup_nlabel(svr->hostname);
+
+ srv_e = rr_create_srv(dup_nlabel(nlabel), port, target); // automatically 4500 seconds
+ rr_list_append(&service->entries, srv_e);
+
+ // create PTR record for type
+ ptr_e = rr_create_ptr(type_nlabel, srv_e); // automatically 4500 seconds
+
+ // create services PTR record for type
+ // this enables the type to show up as a "service"
+ bptr_e = rr_create_ptr(dup_nlabel(SERVICES_DNS_SD_NLABEL), ptr_e); // automatically 4500 seconds
+
+ // modify lists here
+ pthread_mutex_lock(&svr->data_lock);
+
+ if (txt_e)
+ rr_group_add(&svr->group, txt_e);
+ rr_group_add(&svr->group, srv_e);
+ rr_group_add(&svr->group, ptr_e);
+ rr_group_add(&svr->group, bptr_e);
+
+ // append PTR entry to announce list
+ rr_list_append(&svr->announce, ptr_e);
+ rr_list_append(&svr->services, ptr_e);
+
+ pthread_mutex_unlock(&svr->data_lock);
+
+ // don't free type_nlabel - it's with the PTR record
+ free(nlabel);
+ free(inst_nlabel);
+
+ // notify server
+ write_pipe(svr->notify_pipe[1], ".", 1);
+
+ return service;
}
void mdns_service_destroy(struct mdns_service *srv) {
- assert(srv != NULL);
- rr_list_destroy(srv->entries, 0);
- free(srv);
+ assert(srv != NULL);
+ rr_list_destroy(srv->entries, 0);
+ free(srv);
}
struct mdnsd *mdnsd_start() {
- pthread_t tid;
- pthread_attr_t attr;
-
- struct mdnsd *server = malloc(sizeof(struct mdnsd));
- memset(server, 0, sizeof(struct mdnsd));
-
- if (create_pipe(server->notify_pipe) != 0) {
- log_message(LOG_ERR, "pipe(): %m\n");
- free(server);
- return NULL;
- }
-
- server->sockfd = create_recv_sock();
- if (server->sockfd < 0) {
- log_message(LOG_ERR, "unable to create recv socket");
- free(server);
- return NULL;
- }
-
- pthread_mutex_init(&server->data_lock, NULL);
-
- // init thread
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-
- if (pthread_create(&tid, &attr, (void *(*)(void *)) main_loop, (void *) server) != 0) {
- pthread_mutex_destroy(&server->data_lock);
- free(server);
- return NULL;
- }
-
- return server;
+ pthread_t tid;
+ pthread_attr_t attr;
+
+ struct mdnsd *server = malloc(sizeof(struct mdnsd));
+ memset(server, 0, sizeof(struct mdnsd));
+
+ if (create_pipe(server->notify_pipe) != 0) {
+ log_message(LOG_ERR, "pipe(): %m\n");
+ free(server);
+ return NULL;
+ }
+
+ server->sockfd = create_recv_sock();
+ if (server->sockfd < 0) {
+ log_message(LOG_ERR, "unable to create recv socket");
+ free(server);
+ return NULL;
+ }
+
+ pthread_mutex_init(&server->data_lock, NULL);
+
+ // init thread
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+ if (pthread_create(&tid, &attr, (void *(*)(void *))main_loop, (void *)server) != 0) {
+ pthread_mutex_destroy(&server->data_lock);
+ free(server);
+ return NULL;
+ }
+
+ return server;
}
void mdnsd_stop(struct mdnsd *s) {
- assert(s != NULL);
+ assert(s != NULL);
- struct timeval tv = {
- .tv_sec = 0,
- .tv_usec = 500 * 1000,
- };
+ struct timeval tv = {
+ .tv_sec = 0, .tv_usec = 500 * 1000,
+ };
- s->stop_flag = 1;
- write_pipe(s->notify_pipe[1], ".", 1);
+ s->stop_flag = 1;
+ write_pipe(s->notify_pipe[1], ".", 1);
- while (s->stop_flag != 2)
- select(0, NULL, NULL, NULL, &tv);
+ while (s->stop_flag != 2)
+ select(0, NULL, NULL, NULL, &tv);
- close_pipe(s->notify_pipe[0]);
- close_pipe(s->notify_pipe[1]);
+ close_pipe(s->notify_pipe[0]);
+ close_pipe(s->notify_pipe[1]);
- pthread_mutex_destroy(&s->data_lock);
- rr_group_destroy(s->group);
- rr_list_destroy(s->announce, 0);
- rr_list_destroy(s->services, 0);
+ pthread_mutex_destroy(&s->data_lock);
+ rr_group_destroy(s->group);
+ rr_list_destroy(s->announce, 0);
+ rr_list_destroy(s->services, 0);
- if (s->hostname)
- free(s->hostname);
+ if (s->hostname)
+ free(s->hostname);
- free(s);
+ free(s);
}