From aa7053ec1f37d6f1b63cf8d88110617c3dfb962e Mon Sep 17 00:00:00 2001 From: df Date: Sat, 18 Jul 2020 13:49:36 +0100 Subject: [PATCH] Import HummyPkg version --- Makefile | 9 +- README.markdown | 12 --- mdns.c | 254 +++++++++----------------------------------- mdns.h | 24 ----- mdnsd.c | 277 ++++++++++++++++++++---------------------------- mdnsd.h | 3 - testmdnsd.c | 147 +++++++++++++------------ 7 files changed, 242 insertions(+), 484 deletions(-) diff --git a/Makefile b/Makefile index 479575d..a5d72ed 100644 --- a/Makefile +++ b/Makefile @@ -2,17 +2,12 @@ # Makefile for tinysvcmdns # +CC=mipsel-linux-gcc CFLAGS += -Wall -pedantic -std=gnu99 -#CFLAGS += -g CFLAGS += -O2 -DNDEBUG +#CFLAGS += -g LDLIBS = -lpthread -ifneq ($(CROSS_COMPILE),) - CC = gcc - CC := $(CROSS_COMPILE)$(CC) - AR := $(CROSS_COMPILE)$(AR) -endif - BIN=testmdnsd LIBTINYSVCMDNS_OBJS = mdns.o mdnsd.o diff --git a/README.markdown b/README.markdown index 031bf64..abd1bae 100644 --- a/README.markdown +++ b/README.markdown @@ -1,14 +1,3 @@ -NOTICE -======= - -This project is un-maintained, and has been since 2013. - -There are known vulnerabilities that have been disclosed, and quite possibly -others that have yet to be disclosed. Refer to the issue tracker. - -You are advised to NOT use this library for any new projects / products. - - tinysvcmdns ============ tinysvcmdns is a tiny MDNS responder implementation for publishing services. @@ -57,7 +46,6 @@ Copyright (C) 2011 Darell Tan Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright diff --git a/mdns.c b/mdns.c index e4a73f5..6bbc04f 100644 --- a/mdns.c +++ b/mdns.c @@ -32,13 +32,7 @@ #include #include #include - -#ifdef _WIN32 -#include -#include -#else #include -#endif #define DEFAULT_TTL 120 @@ -53,11 +47,13 @@ struct name_comp { // ----- label functions ----- +// compares 2 names +static inline int cmp_nlabel(const uint8_t *L1, const uint8_t *L2) { + return strcmp((char *) L1, (char *) L2); +} + // duplicates a name inline uint8_t *dup_nlabel(const uint8_t *n) { - if (n == NULL) - return NULL; - assert(n[0] <= 63); // prevent mis-use return (uint8_t *) strdup((char *) n); } @@ -93,33 +89,20 @@ uint8_t *join_nlabel(const uint8_t *n1, const uint8_t *n2) { char *nlabel_to_str(const uint8_t *name) { char *label, *labelp; const uint8_t *p; - size_t buf_len = 256; - if (name == NULL) - return NULL; + assert(name != NULL); - label = labelp = malloc(buf_len); + label = labelp = malloc(256); for (p = name; *p; p++) { - uint8_t label_len = *p; - if (buf_len <= label_len) - break; - - strncpy(labelp, (char *) p + 1, label_len); - labelp += label_len; - + strncpy(labelp, (char *) p + 1, *p); + labelp += *p; *labelp = '.'; labelp++; - buf_len -= label_len + 1; - - p += label_len; + p += *p; } - // avoid writing NULL past end of buffer - if (buf_len == 0) - labelp--; - *labelp = '\0'; return label; @@ -153,9 +136,7 @@ uint8_t *create_label(const char *txt) { int len; uint8_t *s; - if (txt == NULL) - return NULL; - + assert(txt != NULL); len = strlen(txt); if (len > 63) return NULL; @@ -270,19 +251,6 @@ static uint8_t *uncompress_nlabel(uint8_t *pkt_buf, size_t pkt_len, size_t off) // ----- 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; -} - void rr_entry_destroy(struct rr_entry *rr) { struct rr_data_txt *txt_rec; assert(rr); @@ -402,13 +370,6 @@ struct rr_entry *rr_create_a(uint8_t *name, uint32_t addr) { 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; - 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); @@ -420,7 +381,6 @@ struct rr_entry *rr_create_srv(uint8_t *name, uint16_t port, uint8_t *target) { 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; } @@ -496,29 +456,12 @@ struct rr_group *rr_group_find(struct rr_group* g, uint8_t *name) { 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) + if (rr->e->type == type) 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; -} - void rr_group_destroy(struct rr_group *group) { struct rr_group *g = group; @@ -531,32 +474,6 @@ void rr_group_destroy(struct rr_group *group) { } } -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; -} - -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; -} - -uint16_t mdns_read_u16(const uint8_t *ptr) { - 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); -} - // 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) { @@ -604,32 +521,22 @@ static size_t mdns_parse_qn(uint8_t *pkt_buf, size_t pkt_len, size_t off, assert(pkt != NULL); rr = malloc(sizeof(struct rr_entry)); - if (rr == NULL) - goto err; - memset(rr, 0, sizeof(struct rr_entry)); name = uncompress_nlabel(pkt_buf, pkt_len, off); - if (name == NULL) - goto err; - p += label_len(pkt_buf, pkt_len, off); rr->name = name; - rr->type = mdns_read_u16(p); + rr->type = ntohs( * (uint16_t *) p ); p += sizeof(uint16_t); rr->unicast_query = (*p & 0x80) == 0x80; - rr->rr_class = mdns_read_u16(p) & ~0x80; + rr->rr_class = ntohs( * (uint16_t *) p) & ~0x80; p += sizeof(uint16_t); rr_list_append(&pkt->rr_qn, rr); return p - (pkt_buf + off); - -err: - free(rr); - return 0; } // parse the MDNS RR section @@ -642,7 +549,6 @@ static size_t mdns_parse_rr(uint8_t *pkt_buf, size_t pkt_len, size_t off, uint8_t *name; size_t rr_data_len = 0; struct rr_data_txt *txt_rec; - int parse_error = 0; assert(pkt != NULL); @@ -650,91 +556,46 @@ static size_t mdns_parse_rr(uint8_t *pkt_buf, size_t pkt_len, size_t off, return 0; rr = malloc(sizeof(struct rr_entry)); - if (rr == NULL) - goto err; - memset(rr, 0, sizeof(struct rr_entry)); name = uncompress_nlabel(pkt_buf, pkt_len, off); - if (name == NULL) - goto err; - p += label_len(pkt_buf, pkt_len, off); rr->name = name; - rr->type = mdns_read_u16(p); + rr->type = ntohs( * (uint16_t *) p ); p += sizeof(uint16_t); rr->cache_flush = (*p & 0x80) == 0x80; - rr->rr_class = mdns_read_u16(p) & ~0x80; + rr->rr_class = ntohs( * (uint16_t *) p) & ~0x80; p += sizeof(uint16_t); - rr->ttl = mdns_read_u32(p); + rr->ttl = ntohl( * (uint32_t *) p ); p += sizeof(uint32_t); // RR data - rr_data_len = mdns_read_u16(p); + rr_data_len = ntohs( * (uint16_t *) 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 */ + rr->data.A.addr = ntohl( * (uint32_t *) p ); 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)); - for (int 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; + if (!txt_rec->txt) break; - } + p += txt_rec->txt[0] + 1; if (p >= e) @@ -752,24 +613,14 @@ static size_t mdns_parse_rr(uint8_t *pkt_buf, size_t pkt_len, size_t off, 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); - -err: - free(rr); - return 0; } // 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; + uint16_t *p = (uint16_t *) pkt_buf; size_t off; struct mdns_pkt *pkt; int i; @@ -780,14 +631,14 @@ struct mdns_pkt *mdns_parse_pkt(uint8_t *pkt_buf, size_t pkt_len) { 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); + pkt->id = ntohs(*p); p++; + pkt->flags = ntohs(*p); p++; + pkt->num_qn = ntohs(*p); p++; + pkt->num_ans_rr = ntohs(*p); p++; + pkt->num_auth_rr = ntohs(*p); p++; + pkt->num_add_rr = ntohs(*p); p++; - off = p - pkt_buf; + off = (uint8_t *) p - pkt_buf; // parse questions for (i = 0; i < pkt->num_qn; i++) { @@ -831,7 +682,7 @@ static size_t mdns_encode_name(uint8_t *pkt_buf, size_t pkt_len, size_t off, // 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)); + *(uint16_t *) p = htons(0xC000 | (c->pos & ~0xC000)); return len + sizeof(uint16_t); } @@ -881,13 +732,16 @@ static size_t mdns_encode_rr(uint8_t *pkt_buf, size_t pkt_len, size_t off, p += l; // type - p = mdns_write_u16(p, rr->type); + *(uint16_t *) p = htons(rr->type); + p += sizeof(uint16_t); // class & cache flush - p = mdns_write_u16(p, (rr->rr_class & ~0x8000) | (rr->cache_flush << 15)); + *(uint16_t *) p = htons((rr->rr_class & ~0x8000) | (rr->cache_flush << 15)); + p += sizeof(uint16_t); // TTL - p = mdns_write_u32(p, rr->ttl); + *(uint32_t *) p = htonl(rr->ttl); + p += sizeof(uint32_t); // data length (filled in later) p += sizeof(uint16_t); @@ -897,13 +751,8 @@ static size_t mdns_encode_rr(uint8_t *pkt_buf, size_t pkt_len, size_t off, 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]; + *(uint32_t *) p = (rr->data.A.addr); + p += sizeof(uint32_t); break; case RR_PTR: @@ -923,11 +772,14 @@ static size_t mdns_encode_rr(uint8_t *pkt_buf, size_t pkt_len, size_t off, break; case RR_SRV: - p = mdns_write_u16(p, rr->data.SRV.priority); + *(uint16_t *) p = htons(rr->data.SRV.priority); + p += sizeof(uint16_t); - p = mdns_write_u16(p, rr->data.SRV.weight); + *(uint16_t *) p = htons(rr->data.SRV.weight); + p += sizeof(uint16_t); - p = mdns_write_u16(p, rr->data.SRV.port); + *(uint16_t *) p = htons(rr->data.SRV.port); + p += sizeof(uint16_t); p += mdns_encode_name(pkt_buf, pkt_len, p - pkt_buf, rr->data.SRV.target, comp); @@ -954,7 +806,7 @@ static size_t mdns_encode_rr(uint8_t *pkt_buf, size_t pkt_len, size_t off, l = p - p_data; // fill in the length - mdns_write_u16(p - l - sizeof(uint16_t), l); + *(uint16_t *) (p - l - sizeof(uint16_t)) = htons(l); return p - pkt_buf - off; } @@ -963,7 +815,7 @@ static size_t mdns_encode_rr(uint8_t *pkt_buf, size_t pkt_len, size_t off, // 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; + uint16_t *p = (uint16_t *) pkt_buf; //uint8_t *e = pkt_buf + pkt_len; size_t off; int i; @@ -977,14 +829,14 @@ size_t mdns_encode_pkt(struct mdns_pkt *answer, uint8_t *pkt_buf, size_t pkt_len // 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); + *p++ = htons(answer->id); + *p++ = htons(answer->flags); + *p++ = htons(answer->num_qn); + *p++ = htons(answer->num_ans_rr); + *p++ = htons(answer->num_auth_rr); + *p++ = htons(answer->num_add_rr); - off = p - pkt_buf; + off = (uint8_t *) p - pkt_buf; // allocate list for name compression comp = malloc(sizeof(struct name_comp)); diff --git a/mdns.h b/mdns.h index e56fc2a..210bc26 100644 --- a/mdns.h +++ b/mdns.h @@ -31,13 +31,6 @@ #include #include -#include - -#ifdef _WIN32 -#include -#else -#include -#endif #define MALLOC_ZERO_STRUCT(x, type) \ x = malloc(sizeof(struct type)); \ @@ -82,10 +75,6 @@ struct rr_data_a { uint32_t addr; }; -struct rr_data_aaaa { - struct in6_addr *addr; -}; - struct rr_entry { uint8_t *name; @@ -116,7 +105,6 @@ struct rr_entry { struct rr_data_txt TXT; struct rr_data_ptr PTR; struct rr_data_a A; - struct rr_data_aaaa AAAA; } data; }; @@ -143,9 +131,6 @@ struct rr_group { #define MDNS_FLAG_GET_RCODE(x) (x & 0x0F) #define MDNS_FLAG_GET_OPCODE(x) ((x >> 11) & 0x0F) -// gets the PTR target name, either from "name" member or "entry" member -#define MDNS_RR_GET_PTR_NAME(rr) (rr->data.PTR.name != NULL ? rr->data.PTR.name : rr->data.PTR.entry->name) - struct mdns_pkt { uint16_t id; // transaction ID uint16_t flags; @@ -169,7 +154,6 @@ void mdns_pkt_destroy(struct mdns_pkt *p); void rr_group_destroy(struct rr_group *group); struct rr_group *rr_group_find(struct rr_group *g, uint8_t *name); struct rr_entry *rr_entry_find(struct rr_list *rr_list, uint8_t *name, uint16_t type); -struct rr_entry *rr_entry_match(struct rr_list *rr_list, struct rr_entry *entry); void rr_group_add(struct rr_group **group, struct rr_entry *rr); int rr_list_count(struct rr_list *rr); @@ -179,14 +163,11 @@ void rr_list_destroy(struct rr_list *rr, char destroy_items); struct rr_entry *rr_create_ptr(uint8_t *name, struct rr_entry *d_rr); struct rr_entry *rr_create_srv(uint8_t *name, uint16_t port, uint8_t *target); -struct rr_entry *rr_create_aaaa(uint8_t *name, struct in6_addr *addr); struct rr_entry *rr_create_a(uint8_t *name, uint32_t addr); struct rr_entry *rr_create(uint8_t *name, enum rr_type type); void rr_set_nsec(struct rr_entry *rr_nsec, enum rr_type type); void rr_add_txt(struct rr_entry *rr_txt, const char *txt); -const char *rr_get_type_name(enum rr_type type); - uint8_t *create_label(const char *txt); uint8_t *create_nlabel(const char *name); char *nlabel_to_str(const uint8_t *name); @@ -194,9 +175,4 @@ uint8_t *dup_label(const uint8_t *label); uint8_t *dup_nlabel(const uint8_t *n); uint8_t *join_nlabel(const uint8_t *n1, const uint8_t *n2); -// compares 2 names -static inline int cmp_nlabel(const uint8_t *L1, const uint8_t *L2) { - return strcmp((char *) L1, (char *) L2); -} - #endif /*!__MDNS_H__*/ diff --git a/mdnsd.c b/mdnsd.c index 6488a53..b4ae9fa 100644 --- a/mdnsd.c +++ b/mdnsd.c @@ -26,22 +26,15 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifdef _WIN32 -#include -#include -#define LOG_ERR 3 -#else -#include #include #include #include #include #include -#include -#endif #include #include +#include #include #include #include @@ -51,20 +44,15 @@ #include #include #include - -/* - * Define a proper IP socket level if not already done. - * Required to compile on OS X - */ -#ifndef SOL_IP -#define SOL_IP IPPROTO_IP -#endif +#include #include "mdns.h" #include "mdnsd.h" #define MDNS_ADDR "224.0.0.251" #define MDNS_PORT 5353 +#define LLMNR_ADDR "224.0.0.252" +#define LLMNR_PORT 5355 #define PACKET_SIZE 65536 @@ -74,6 +62,7 @@ struct mdnsd { pthread_mutex_t data_lock; int sockfd; + int llmnrfd; int notify_pipe[2]; int stop_flag; @@ -102,7 +91,7 @@ static void log_message(int loglevel, char *fmt_str, ...) { fprintf(stderr, "%s\n", buf); } -static int create_recv_sock() { +static int create_recv_sock(char *addr, int port) { int sd = socket(AF_INET, SOCK_DGRAM, 0); if (sd < 0) { log_message(LOG_ERR, "recv socket(): %m"); @@ -121,7 +110,7 @@ static int create_recv_sock() { struct sockaddr_in serveraddr; memset(&serveraddr, 0, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; - serveraddr.sin_port = htons(MDNS_PORT); + serveraddr.sin_port = htons(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"); @@ -131,7 +120,7 @@ static int create_recv_sock() { 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); + mreq.imr_multiaddr.s_addr = inet_addr(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; @@ -166,11 +155,28 @@ static ssize_t send_packet(int fd, const void *data, size_t len) { return sendto(fd, data, len, 0, (struct sockaddr *) &toaddr, sizeof(struct sockaddr_in)); } +static ssize_t send_llmnr_packet(int fd, struct sockaddr_in *from, const void *data, size_t len) { +#if 0 + static struct sockaddr_in toaddr; + + memset(&toaddr, 0, sizeof(struct sockaddr_in)); + toaddr.sin_family = AF_INET; + toaddr.sin_port = from->sin_port; + toaddr.sin_addr.s_addr = inet_addr(LLMNR_ADDR); + + return sendto(fd, data, len, 0, (struct sockaddr *) &toaddr, sizeof(struct sockaddr_in)); +#else + return sendto(fd, data, len, 0, (struct sockaddr *)from, + sizeof(struct sockaddr_in)); +#endif +} + // 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; + struct rr_entry *rr; // check if we have the records pthread_mutex_lock(&svr->data_lock); @@ -180,18 +186,22 @@ static int populate_answers(struct mdnsd *svr, struct rr_list **rr_head, uint8_t 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; + // include all records? + if (type == RR_ANY) { + struct rr_list *n = ans_grp->rr; + for (; n; n = n->next) { + // exclude NSEC + if (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); } + } else { + // match record type + rr = rr_entry_find(ans_grp->rr, name, type); + if (rr) + num_ans += rr_list_append(rr_head, rr); } - pthread_mutex_unlock(&svr->data_lock); return num_ans; @@ -206,7 +216,10 @@ static void add_related_rr(struct mdnsd *svr, struct rr_list *list, struct mdns_ 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); + (ans->data.PTR.name ? + ans->data.PTR.name : + ans->data.PTR.entry->name), + RR_ANY); break; case RR_SRV: @@ -272,10 +285,8 @@ static int process_mdns_pkt(struct mdnsd *svr, struct mdns_pkt *pkt, struct mdns 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; - 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); + DEBUG_PRINTF("qn #%d: type 0x%02x %s - ", i, qn->type, namestr); free(namestr); // check if it's a unicast query - we ignore those @@ -284,41 +295,16 @@ static int process_mdns_pkt(struct mdnsd *svr, struct mdns_pkt *pkt, struct mdns continue; } - num_ans_added = populate_answers(svr, &reply->rr_ans, qn->name, qn->type); - reply->num_ans_rr += num_ans_added; - - DEBUG_PRINTF("added %d answers\n", 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); - - // 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); - - // check if list item is head - if (prev_ans == NULL) - reply->rr_ans = ans->next; - else - prev_ans->next = ans->next; - free(ans); - - ans = prev_ans; - - // adjust answer count - reply->num_ans_rr--; + // see if it is in the answers + if (rr_entry_find(pkt->rr_ans, qn->name, qn->type)) { + DEBUG_PRINTF("our record is already in their answers\n"); + continue; } - prev_ans = ans; - ans = next_ans; - } + reply->num_ans_rr += populate_answers(svr, &reply->rr_ans, qn->name, qn->type); + DEBUG_PRINTF("adding %d answers\n", reply->num_ans_rr); + } // see if we can match additional records for answers add_related_rr(svr, reply->rr_ans, reply); @@ -334,104 +320,39 @@ static int process_mdns_pkt(struct mdnsd *svr, struct mdns_pkt *pkt, struct mdns 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; -#else - return pipe(handles); -#endif -} - -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; -#else - return read(s, buf, len); -#endif -} - -int write_pipe(int s, char* buf, int len) { -#ifdef _WIN32 - return send(s, buf, len, 0); -#else - return write(s, buf, len); -#endif -} - -int close_pipe(int s) { -#ifdef _WIN32 - return closesocket(s); -#else - 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]; + if (svr->llmnrfd > max_fd) + max_fd = svr->llmnrfd; struct mdns_pkt *mdns_reply = malloc(sizeof(struct mdns_pkt)); memset(mdns_reply, 0, sizeof(struct mdns_pkt)); while (! svr->stop_flag) { + struct timeval tv = { + .tv_sec = 3600, + .tv_usec = 0, + }; + FD_ZERO(&sockfd_set); FD_SET(svr->sockfd, &sockfd_set); + FD_SET(svr->llmnrfd, &sockfd_set); FD_SET(svr->notify_pipe[0], &sockfd_set); - select(max_fd + 1, &sockfd_set, NULL, NULL, NULL); + select(max_fd + 1, &sockfd_set, NULL, NULL, &tv); if (FD_ISSET(svr->notify_pipe[0], &sockfd_set)) { - // flush the notify_pipe - read_pipe(svr->notify_pipe[0], (char*)¬ify_buf, 1); - } else if (FD_ISSET(svr->sockfd, &sockfd_set)) { + read(svr->notify_pipe[0], pkt_buffer, PACKET_SIZE); + } + + if (FD_ISSET(svr->sockfd, &sockfd_set)) { struct sockaddr_in fromaddr; socklen_t sockaddr_size = sizeof(struct sockaddr_in); @@ -447,8 +368,28 @@ static void main_loop(struct mdnsd *svr) { 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); + } + } + + if (FD_ISSET(svr->llmnrfd, &sockfd_set)) { + struct sockaddr_in fromaddr; + socklen_t sockaddr_size = sizeof(struct sockaddr_in); + + ssize_t recvsize = recvfrom(svr->llmnrfd, pkt_buffer, PACKET_SIZE, 0, + (struct sockaddr *) &fromaddr, &sockaddr_size); + if (recvsize < 0) { + log_message(LOG_ERR, "recv(): %m"); + } + + DEBUG_PRINTF("LLMNR 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_llmnr_packet(svr->llmnrfd, &fromaddr, pkt_buffer, replylen); } mdns_pkt_destroy(mdns); @@ -505,7 +446,8 @@ static void main_loop(struct mdnsd *svr) { free(pkt_buffer); - close_pipe(svr->sockfd); + close(svr->sockfd); + close(svr->llmnrfd); svr->stop_flag = 2; } @@ -514,28 +456,32 @@ static void main_loop(struct mdnsd *svr) { void mdnsd_set_hostname(struct mdnsd *svr, const char *hostname, uint32_t ip) { - struct rr_entry *a_e = NULL, - *nsec_e = NULL; + + struct rr_entry *a_e, *nsec_e; + struct rr_entry *al_e, *nsecl_e; + char hostnamel[0x100]; // currently can't be called twice // dont ask me what happens if the IP changes assert(svr->hostname == NULL); + sprintf(hostnamel, "%s.local", hostname); + a_e = rr_create_a(create_nlabel(hostname), ip); + a_e->cache_flush = 0; + //nsec_e = rr_create(create_nlabel(hostname), RR_NSEC); + //rr_set_nsec(nsec_e, RR_A); - nsec_e = rr_create(create_nlabel(hostname), RR_NSEC); - rr_set_nsec(nsec_e, RR_A); + al_e = rr_create_a(create_nlabel(hostnamel), ip); + nsecl_e = rr_create(create_nlabel(hostnamel), RR_NSEC); + rr_set_nsec(nsecl_e, RR_A); pthread_mutex_lock(&svr->data_lock); - svr->hostname = create_nlabel(hostname); + svr->hostname = create_nlabel(hostnamel); rr_group_add(&svr->group, a_e); - rr_group_add(&svr->group, nsec_e); - pthread_mutex_unlock(&svr->data_lock); -} - -void mdnsd_add_rr(struct mdnsd *svr, struct rr_entry *rr) { - pthread_mutex_lock(&svr->data_lock); - rr_group_add(&svr->group, rr); + //rr_group_add(&svr->group, nsec_e); + rr_group_add(&svr->group, al_e); + rr_group_add(&svr->group, nsecl_e); pthread_mutex_unlock(&svr->data_lock); } @@ -601,7 +547,7 @@ struct mdns_service *mdnsd_register_svc(struct mdnsd *svr, const char *instance_ free(inst_nlabel); // notify server - write_pipe(svr->notify_pipe[1], ".", 1); + write(svr->notify_pipe[1], ".", 1); return service; } @@ -619,19 +565,26 @@ struct mdnsd *mdnsd_start() { struct mdnsd *server = malloc(sizeof(struct mdnsd)); memset(server, 0, sizeof(struct mdnsd)); - if (create_pipe(server->notify_pipe) != 0) { + if (pipe(server->notify_pipe) != 0) { log_message(LOG_ERR, "pipe(): %m\n"); free(server); return NULL; } - server->sockfd = create_recv_sock(); + server->sockfd = create_recv_sock(MDNS_ADDR, MDNS_PORT); if (server->sockfd < 0) { log_message(LOG_ERR, "unable to create recv socket"); free(server); return NULL; } + server->llmnrfd = create_recv_sock(LLMNR_ADDR, LLMNR_PORT); + if (server->llmnrfd < 0) { + log_message(LOG_ERR, "unable to create llmnr recv socket"); + free(server); + return NULL; + } + pthread_mutex_init(&server->data_lock, NULL); // init thread @@ -656,13 +609,13 @@ void mdnsd_stop(struct mdnsd *s) { }; s->stop_flag = 1; - write_pipe(s->notify_pipe[1], ".", 1); + write(s->notify_pipe[1], ".", 1); while (s->stop_flag != 2) select(0, NULL, NULL, NULL, &tv); - close_pipe(s->notify_pipe[0]); - close_pipe(s->notify_pipe[1]); + close(s->notify_pipe[0]); + close(s->notify_pipe[1]); pthread_mutex_destroy(&s->data_lock); rr_group_destroy(s->group); diff --git a/mdnsd.h b/mdnsd.h index 99f1b86..c820f96 100644 --- a/mdnsd.h +++ b/mdnsd.h @@ -44,9 +44,6 @@ void mdnsd_stop(struct mdnsd *s); // sets the hostname for the given MDNS responder instance void mdnsd_set_hostname(struct mdnsd *svr, const char *hostname, uint32_t ip); -// adds an additional RR -void mdnsd_add_rr(struct mdnsd *svr, struct rr_entry *rr); - // registers a service with the MDNS responder instance 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[]); diff --git a/testmdnsd.c b/testmdnsd.c index ebe607d..2930db2 100644 --- a/testmdnsd.c +++ b/testmdnsd.c @@ -1,96 +1,93 @@ -/* - * tinysvcmdns - a tiny MDNS implementation for publishing services - * Copyright (C) 2011 Darell Tan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef _WIN32 -#include -#include -#include -#else -#include -#include -#include -#endif - #include +#include +#include +#include +#include +#include +#include +#include +#include #include "mdns.h" #include "mdnsd.h" -int main(int argc, char *argv[]) { - // create host entries - char *hostname = "some-random-host.local"; +void +background() +{ + int fd; + + switch ((int)fork()) + { + case -1: + perror("fork"); + exit(1); + case 0: + break; + default: + exit(0); + } + +#ifdef TIOCNOTTY + if (ioctl(fileno(stdin), TIOCNOTTY) == -1) + perror("detach_console"); +#endif + freopen("/dev/null", "r", stdin); + + fd = open("/dev/null", O_WRONLY, 0666); + dup2(fd, fileno(stdout)); + dup2(fd, fileno(stderr)); + close(fd); + + setsid(); +} + +int +main(int argc, char **argv) +{ + char hostname[0x100], ifname[0x100]; + struct hostent *hp; + struct in_addr saddr; + + if (gethostname(hostname, sizeof(hostname) - 1) == -1) + { + printf("Couldn't retrieve humax hostname.\n"); + return 1; + } + + if (!(hp = gethostbyname(hostname))) + { + printf("Couldn't retrieve humax IP address.\n"); + return 1; + } + memmove((char *)&saddr.s_addr, (char *)hp->h_addr, + sizeof(saddr.s_addr)); + printf("Hostname: %s (%s)\n", hostname, inet_ntoa(saddr)); struct mdnsd *svr = mdnsd_start(); if (svr == NULL) { printf("mdnsd_start() error\n"); return 1; } + printf("Started MDNS Service\n"); - printf("mdnsd_start OK. press ENTER to add hostname & service\n"); - getchar(); + mdnsd_set_hostname(svr, hostname, saddr.s_addr); - mdnsd_set_hostname(svr, hostname, inet_addr("192.168.0.29")); - - struct rr_entry *a2_e = NULL; - a2_e = rr_create_a(create_nlabel(hostname), inet_addr("192.168.0.31")); - mdnsd_add_rr(svr, a2_e); - - struct rr_entry *aaaa_e = NULL; - - struct addrinfo hints; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET6; - hints.ai_flags = AI_NUMERICHOST; - struct addrinfo* results; - getaddrinfo( - "fe80::e2f8:47ff:fe20:28e0", - NULL, - &hints, - &results); - struct sockaddr_in6* addr = (struct sockaddr_in6*)results->ai_addr; - struct in6_addr v6addr = addr->sin6_addr; - freeaddrinfo(results); - - aaaa_e = rr_create_aaaa(create_nlabel(hostname), &v6addr); - - mdnsd_add_rr(svr, aaaa_e); + sprintf(ifname, "Humax Fox T2 (%s) Web Interface", hostname); const char *txt[] = { - "path=/mywebsite", + "path=/", NULL }; - struct mdns_service *svc = mdnsd_register_svc(svr, "My Website", - "_http._tcp.local", 8080, NULL, txt); - mdns_service_destroy(svc); + struct mdns_service *svc = mdnsd_register_svc( + svr, ifname, "_http._tcp.local", 80, + NULL, txt); + //mdns_service_destroy(svc); - printf("added service and hostname. press ENTER to exit\n"); - getchar(); + printf("Registered name.\n"); - mdnsd_stop(svr); + for (;;) + sleep(3600); + + // mdnsd_stop(svr); return 0; }