Import HummyPkg version
This commit is contained in:
parent
16f0faf3ce
commit
aa7053ec1f
9
Makefile
9
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
|
||||
|
@ -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
|
||||
|
254
mdns.c
254
mdns.c
@ -32,13 +32,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock.h>
|
||||
#include <in6addr.h>
|
||||
#else
|
||||
#include <netinet/in.h>
|
||||
#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));
|
||||
|
24
mdns.h
24
mdns.h
@ -31,13 +31,6 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock.h>
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#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__*/
|
||||
|
277
mdnsd.c
277
mdnsd.c
@ -26,22 +26,15 @@
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#define LOG_ERR 3
|
||||
#else
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <net/if.h>
|
||||
#include <syslog.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/select.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
@ -51,20 +44,15 @@
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
|
||||
/*
|
||||
* 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 <syslog.h>
|
||||
|
||||
#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);
|
||||
|
3
mdnsd.h
3
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[]);
|
||||
|
147
testmdnsd.c
147
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 <winsock2.h>
|
||||
#include <in6addr.h>
|
||||
#include <ws2tcpip.h>
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <string.h>
|
||||
#include <netdb.h>
|
||||
#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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user