Compare commits
28 Commits
Author | SHA1 | Date | |
---|---|---|---|
56cfa698a4 | |||
3b8db036a1 | |||
59368bb111 | |||
c6b9730299 | |||
e436becbbd | |||
302d113377 | |||
a9dcc648ae | |||
75af91d0cc | |||
ec6463e6c4 | |||
ba051c353a | |||
46a74b3c06 | |||
7223f118a7 | |||
cfdf09a1dc | |||
d7c62ad55c | |||
964c2dd28d | |||
0aa116dbce | |||
2ce1bb8ae4 | |||
17ef47d6f2 | |||
3c1f038fbc | |||
de3042f808 | |||
3a24c51c56 | |||
90d70d13b1 | |||
aa472217c5 | |||
e42e88d61f | |||
c9a1e4cf0d | |||
8f15f5873b | |||
ed03a6098d | |||
8b2f04c2ea |
48
Makefile
48
Makefile
@ -2,9 +2,16 @@
|
||||
# Makefile for tinysvcmdns
|
||||
#
|
||||
|
||||
MV ?= mv
|
||||
|
||||
CPPFLAGS += -DPTHREAD_CREATE_DETACHED_SUPPORTED
|
||||
#CPPFLAGS += -DNDEBUG
|
||||
CPPFLAGS += $(CPPFLAGS_EXTRA)
|
||||
|
||||
CFLAGS += -Wall -pedantic -std=gnu99
|
||||
#CFLAGS += -g
|
||||
CFLAGS += -O2 -DNDEBUG
|
||||
CFLAGS += -g
|
||||
CFLAGS += -O2
|
||||
CFLAGS += $(CFLAGS_EXTRA)
|
||||
LDLIBS = -lpthread
|
||||
|
||||
ifneq ($(CROSS_COMPILE),)
|
||||
@ -13,26 +20,49 @@ ifneq ($(CROSS_COMPILE),)
|
||||
AR := $(CROSS_COMPILE)$(AR)
|
||||
endif
|
||||
|
||||
BIN=testmdnsd
|
||||
BIN=testmdnsd mdnsd
|
||||
|
||||
LIBTINYSVCMDNS_OBJS = mdns.o mdnsd.o
|
||||
|
||||
.PHONY: all clean
|
||||
.PHONY: all clean opkg release opkg-service opkg-init
|
||||
|
||||
all: $(BIN) libtinysvcmdns.a
|
||||
|
||||
clean:
|
||||
-$(RM) *.o
|
||||
-$(RM) *.bin
|
||||
-$(RM) mdns
|
||||
-$(RM) $(LIBTINYSVCMDNS_OBJS)
|
||||
-$(RM) $(BIN)
|
||||
-$(RM) libtinysvcmdns.a
|
||||
|
||||
mdns: mdns.o
|
||||
mdns.o: mdns.h
|
||||
|
||||
mdnsd: mdns.o mdnsd.o
|
||||
mdnsd.o: mdns.h mdnsd.h
|
||||
|
||||
testmdnsd.o: mdnsd.h
|
||||
|
||||
testmdnsd: testmdnsd.o libtinysvcmdns.a
|
||||
|
||||
libtinysvcmdns.a: $(patsubst %, libtinysvcmdns.a(%), $(LIBTINYSVCMDNS_OBJS))
|
||||
|
||||
mdnsd: testmdnsd
|
||||
strip -o $@ $<
|
||||
|
||||
opkg-init: $(wildcard etc/init.d/*)
|
||||
install -d opkg/etc/init.d
|
||||
install -p $? opkg/etc/init.d/
|
||||
|
||||
opkg-service: $(wildcard etc/modservice.d/*)
|
||||
install -d opkg/etc/modservice.d
|
||||
install -m 644 -p $? opkg/etc/modservice.d/
|
||||
|
||||
opkg: mdnsd $(wildcard opkg/CONTROL/*) opkg-init opkg-service
|
||||
install -d opkg/sbin
|
||||
install -p $< opkg/sbin/
|
||||
$(foreach opk,$(wildcard *.opk),$(MV) $(opk) $(opk).old; )
|
||||
opkg-pack opkg
|
||||
|
||||
release: opkg
|
||||
tagname=$$(echo zeroconf*.opk | sed -n 'p;q') && \
|
||||
tagname="$${tagname%_*.*}" && \
|
||||
test -n "$${tagname}" && \
|
||||
git tag -f -a -m "Release $${tagname}" "$${tagname}"
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
NOTICE
|
||||
=======
|
||||
NOTICE FROM THE ORIGINAL AUTHOR
|
||||
-------------------------------
|
||||
|
||||
This project is un-maintained, and has been since 2013.
|
||||
|
||||
@ -27,26 +27,25 @@ Decoding of MDNS packets is only done to retrieve the questions and answer RRs.
|
||||
The purpose for decoding answer RRs is to make sure the service PTR is not
|
||||
sent out if it is already included in the answer RRs.
|
||||
|
||||
It also only utilizes multicast packets, so no "QU" queries are accepted.
|
||||
|
||||
There is no name collision detection, so this means no queries are generated
|
||||
before publishing the services. However compliant responders will avoid using
|
||||
our names, since the implementation will respond to queries that match our
|
||||
name.
|
||||
|
||||
|
||||
TODO
|
||||
-----
|
||||
* better, more stable & complete API
|
||||
* name collision detection
|
||||
|
||||
Unicast queries are accepted but only legacy queries (non-mDNS source port) get a unicast response (think `dig`).
|
||||
|
||||
FILES
|
||||
------
|
||||
* mdns.c - provides data structures, parsing & encoding of MDNS packets
|
||||
* mdns.h - interface to the above
|
||||
* mdnsd.c - implements the server socket, communication and thread
|
||||
* mdnsd.h - interface to the above
|
||||
* testmdnsd.c - an example that creates an instance until terminated
|
||||
|
||||
HISTORY
|
||||
-------
|
||||
Darell Tan is the original author. His version, to which the Notice above refers, can be found at https://bitbucket.org/geekman/tinysvcmdns, and in a branch of this repository. Several forked versions can be found across the Internet. The version at https://github.com/philippe44/TinySVCmDNS is adapted for more platforms and addresses some of the issues in the original version. Meanwhile, the code was adopted as part of Samsung's TizenRT [IOT](https://www.briansolis.com/tag/internet-of-shit/) framework, but without maintaining the change history between that version and the original. The TizenRT version implemented most of the RFC 6762/6763 features missing from the original version, and also fixed the known vulnerabilities mentioned in the Notice.
|
||||
|
||||
In 2012 the original version was [adapted as a package](https://hummy.tv/forum/threads/announcing-dns-name-on-upnp-for-webif.1640/) for the [Custom Firmware](https://hummy.tv/forum/forums/hd-hdr-fox-t2-customised-firmware.28/) on the Humax HD/R-Fox T2 TV set-top boxes. This fork (let's call it HummyPkg) differed mostly in the `testmdnsd.c` program which was specialised for the package. However it did not track the changes in the original version. The branch named HummyPkg does so.
|
||||
|
||||
The HummyPkg version enabled other LAN devices to find the tinysvcmdns host, but only if they were able to resolve names by querying the mDNS service; this excluded other Humax CF boxes as they rely on a `hosts` file for name resolution. It also had to be restarted if the LAN IP address of the tinysvcmdns host changed, as would happen at startup using a WiFi dongle.
|
||||
|
||||
By reabsorbing the changes from the TizenRT version into the HummyPkg version and making some further enhancements, it has been possible to create a version named HummyNew that addresses those issues. This comprises a highly modified `testmdnsd.c` that can parse and write `hosts` files together with an almost fully featured mDNS implementation.
|
||||
|
||||
LICENSE
|
||||
--------
|
||||
|
32
etc/init.d/S80mdnsd
Executable file
32
etc/init.d/S80mdnsd
Executable file
@ -0,0 +1,32 @@
|
||||
#!/bin/sh
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
# Wait for network to come up...
|
||||
(
|
||||
while [ ! -f /tmp/if-up ]; do
|
||||
echo "mdnsd: waiting for network..."
|
||||
sleep 1
|
||||
done
|
||||
|
||||
interface="`/sbin/route | /bin/sed -n '$ {
|
||||
s/.* //
|
||||
p
|
||||
}'`"
|
||||
echo " MDNS interface: [$interface]"
|
||||
[ -z "$interface" ] && interface=eth0
|
||||
|
||||
/bin/ip route add 224.0.0.0/4 dev $interface
|
||||
/mod/sbin/mdnsd &
|
||||
) &
|
||||
;;
|
||||
stop)
|
||||
killall -q mdnsd
|
||||
;;
|
||||
*)
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
|
3
etc/modservice.d/mdnsd
Normal file
3
etc/modservice.d/mdnsd
Normal file
@ -0,0 +1,3 @@
|
||||
key=/mod/sbin/mdnsd
|
||||
rc=80mdnsd
|
||||
proc=$key
|
49
mdns.h
49
mdns.h
@ -32,6 +32,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock.h>
|
||||
@ -39,18 +40,53 @@
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
/* see RFC 6762 Section 10 */
|
||||
#define DEFAULT_TTL_FOR_RECORD_WITH_HOSTNAME 120
|
||||
#define DEFAULT_TTL 4500
|
||||
/* see RFC 6762 Section 5.4 */
|
||||
#define DEFAULT_TTL_LEGACY 10
|
||||
|
||||
#ifndef MDNS_DEBUG_PRINTF
|
||||
#define MDNS_DEBUG_PRINTF 0
|
||||
#endif
|
||||
|
||||
#if MDNS_DEBUG_PRINTF==1
|
||||
#define MDNS_RR_DEBUG 0
|
||||
#define MDNS_MEMORY_DEBUG 0
|
||||
#endif
|
||||
|
||||
#if MDNS_DEBUG_PRINTF==1 && MDNS_MEMORY_DEBUG==1
|
||||
void *mdns_malloc(const char *func_name, int line, unsigned int size);
|
||||
void mdns_free(const char *func_name, int line, void *ptr);
|
||||
char *mdns_strdup(const char *func_name, int line, const char *str);
|
||||
void mdns_show_meminfo(void);
|
||||
|
||||
#define MDNS_MALLOC(size) mdns_malloc(__FUNCTION__, __LINE__, size)
|
||||
#define MDNS_FREE(ptr) mdns_free(__FUNCTION__, __LINE__, ptr)
|
||||
#define MDNS_STRDUP(str) mdns_strdup(__FUNCTION__, __LINE__, str)
|
||||
|
||||
#else
|
||||
#define MDNS_MALLOC(size) malloc(size)
|
||||
#define MDNS_FREE(ptr) free(ptr)
|
||||
#define MDNS_STRDUP(size) strdup(size)
|
||||
#endif
|
||||
#define MALLOC_ZERO_STRUCT(x, type) \
|
||||
x = malloc(sizeof(struct type)); \
|
||||
memset(x, 0, sizeof(struct type));
|
||||
x = MDNS_MALLOC(sizeof(struct type)); \
|
||||
memset(x, 0, sizeof(struct type))
|
||||
|
||||
#define DECL_MALLOC_ZERO_STRUCT(x, type) \
|
||||
struct type * MALLOC_ZERO_STRUCT(x, type)
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define DECL_ZERO_STRUCT(_x, _type) \
|
||||
struct _type _x; \
|
||||
memset(&(_x), 0, sizeof(struct _type))
|
||||
|
||||
#if MDNS_DEBUG_PRINTF==1
|
||||
#define DEBUG_PRINTF(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
#define DEBUG_PRINTF(...) ((void) 0)
|
||||
#endif
|
||||
#define MDNS_RR_DEBUG_PRINTF(...) printf(__VA_ARGS__)
|
||||
|
||||
|
||||
struct rr_data_srv {
|
||||
@ -118,6 +154,7 @@ struct rr_entry {
|
||||
struct rr_data_a A;
|
||||
struct rr_data_aaaa AAAA;
|
||||
} data;
|
||||
time_t update_time;
|
||||
};
|
||||
|
||||
struct rr_list {
|
||||
@ -162,8 +199,9 @@ struct mdns_pkt {
|
||||
|
||||
struct mdns_pkt *mdns_parse_pkt(uint8_t *pkt_buf, size_t pkt_len);
|
||||
|
||||
void mdns_init_query(struct mdns_pkt *pkt, uint16_t id);
|
||||
void mdns_init_reply(struct mdns_pkt *pkt, uint16_t id);
|
||||
size_t mdns_encode_pkt(struct mdns_pkt *answer, uint8_t *pkt_buf, size_t pkt_len);
|
||||
size_t mdns_encode_pkt(struct mdns_pkt *encoded_pkt, uint8_t *pkt_buf, size_t pkt_len);
|
||||
|
||||
void mdns_pkt_destroy(struct mdns_pkt *p);
|
||||
void rr_group_destroy(struct rr_group *group);
|
||||
@ -171,17 +209,20 @@ 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);
|
||||
void rr_group_del(struct rr_group **group, struct rr_entry *rr);
|
||||
|
||||
int rr_list_count(struct rr_list *rr);
|
||||
int rr_list_append(struct rr_list **rr_head, struct rr_entry *rr);
|
||||
struct rr_entry *rr_list_remove(struct rr_list **rr_head, struct rr_entry *rr);
|
||||
void rr_list_destroy(struct rr_list *rr, char destroy_items);
|
||||
|
||||
struct rr_entry *qn_create(uint8_t *name, enum rr_type type, int unicast_query);
|
||||
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);
|
||||
struct rr_entry *rr_duplicate(struct rr_entry *rr_src);
|
||||
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);
|
||||
|
||||
|
113
mdnsd.h
113
mdnsd.h
@ -25,6 +25,7 @@
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/* APIs for Multicast DNS */
|
||||
|
||||
#ifndef __MDNSD_H__
|
||||
#define __MDNSD_H__
|
||||
@ -34,12 +35,76 @@
|
||||
struct mdnsd;
|
||||
struct mdns_service;
|
||||
|
||||
// starts a MDNS responder instance
|
||||
// returns NULL if unsuccessful
|
||||
struct mdnsd *mdnsd_start();
|
||||
#define MAX_NUMBER_OF_SERVICE_DISCOVERY_RESULT 10
|
||||
#define MAX_SERVICE_DISCOVERY_TIME_MS (60 * 1000)
|
||||
|
||||
// stops the given MDNS responder instance
|
||||
void mdnsd_stop(struct mdnsd *s);
|
||||
#define MDNS_HOSTNAME_RESOLVER_TIMEOUT_MSEC (3 * 1000)
|
||||
#define MDNS_HOSTNAME_RESOLVER_MAX_TRY_COUNT 5
|
||||
#define MDNS_HOSTNAME_RESOLVER_WAIT_TIME_MSEC 250
|
||||
|
||||
#define MDNS_SERVICE_DISCOVERY_MAX_TRY_COUNT 5
|
||||
#define MDNS_SERVICE_DISCOVERY_WAIT_TIME_MSEC 250
|
||||
|
||||
/* Structure of MDNS service information */
|
||||
struct mdns_service_info {
|
||||
char *type;
|
||||
char *instance_name;
|
||||
char *hostname;
|
||||
unsigned int ipaddr; /* ipv4 */
|
||||
unsigned int port;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
#ifndef MDNS_NO_RESPONDER_SUPPORT
|
||||
|
||||
/**
|
||||
* starts the MDNS daemon.
|
||||
*
|
||||
* [in] desired_hostname the desired host name as string type; if same name is in the network, an alternative name will be set as hostname.
|
||||
* [in] netif_name network interface name as string type
|
||||
* On success, 0 is returned. On failure, a negative value is returned.
|
||||
*
|
||||
*/
|
||||
int mdnsd_start(const char *desired_hostname, const char *netif_name);
|
||||
|
||||
/**
|
||||
* mdnsd_stop() stops the MDNS daemon.
|
||||
*
|
||||
* On success, 0 is returned. On failure, a negative value is returned.
|
||||
*
|
||||
*/
|
||||
int mdnsd_stop(void);
|
||||
|
||||
/**
|
||||
* mdnsd_get_hostname() gets the current host name as MDNS type.
|
||||
*
|
||||
* [out] hostname_result 32-bytes string buffer for the host name result
|
||||
* On success, 0 is returned. On failure, a negative value is returned.
|
||||
*
|
||||
*/
|
||||
int mdnsd_get_hostname(char *hostname_result);
|
||||
|
||||
/**
|
||||
* mdnsd_register_service() register a service to expose through mDNS-SD.
|
||||
*
|
||||
* [in] instance instance name to expose
|
||||
* [in] type type of service. e.g. _http._tcp.local
|
||||
* [in] port port to which the service is reachable
|
||||
* [in] hostname if NULL, use the hostname configured when starting the daemon,
|
||||
* or use this parameter otherwise
|
||||
* [in] txt text records to add to the service announcement. Can be NULL.
|
||||
* On success, 0 is returned. On failure, a negative errno value is returned.
|
||||
*
|
||||
*/
|
||||
int mdnsd_register_service(const char *instance, const char *type,
|
||||
uint16_t port, const char *hostname, const char *txt[]);
|
||||
|
||||
// sets the hostname for the given MDNS responder instance
|
||||
void mdnsd_set_hostname(struct mdnsd *svr, const char *hostname, uint32_t ip);
|
||||
@ -48,11 +113,41 @@ void mdnsd_set_hostname(struct mdnsd *svr, const char *hostname, uint32_t ip);
|
||||
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[]);
|
||||
//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[]);
|
||||
|
||||
// destroys the mdns_service struct returned by mdnsd_register_svc()
|
||||
void mdns_service_destroy(struct mdns_service *srv);
|
||||
//void mdns_service_destroy(struct mdns_service *srv);
|
||||
|
||||
#endif /* !defined MDNS_NO_RESPONDER_SUPPORT */
|
||||
|
||||
/**
|
||||
* mdnsd_resolve_hostname() gets ip address with the given hostname.
|
||||
*
|
||||
* [in] hostname host name as string type
|
||||
* [out] ipaddr the pointer of ip address result
|
||||
* On success, 0 is returned. On failure, a negative value is returned.
|
||||
*
|
||||
*/
|
||||
int mdnsd_resolve_hostname(char *hostname, uint32_t *ipaddr);
|
||||
|
||||
/**
|
||||
* mdnsd_discover_service() discovers services with the given service type string
|
||||
*
|
||||
* [in] service_type mdns service type string
|
||||
* [in] discover_time_msec time in milliseconds for discovering service
|
||||
* [out] service_list the array of service list
|
||||
* [out] num_of_services number of services
|
||||
* On success, 0 is returned. On failure, a negative value is returned.
|
||||
*
|
||||
*/
|
||||
int mdnsd_discover_service(char *service_type, int discover_time_msec, struct mdns_service_info **service_list, int *num_of_services);
|
||||
|
||||
|
||||
#endif/*!__MDNSD_H__*/
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*!__MDNSD_H__ */
|
||||
|
||||
|
8
opkg/CONTROL/control
Normal file
8
opkg/CONTROL/control
Normal file
@ -0,0 +1,8 @@
|
||||
Package: zeroconf
|
||||
Priority: optional
|
||||
Section: net
|
||||
Version: 2.0-2
|
||||
Architecture: mipsel
|
||||
Maintainer: af123@hummypkg.org.uk
|
||||
Depends:
|
||||
Description: MDNS server, enables name resolution for received .local names
|
8
opkg/CONTROL/postinst
Executable file
8
opkg/CONTROL/postinst
Executable file
@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
|
||||
for action in stop start; do
|
||||
/mod/etc/init.d/S80mdnsd $action
|
||||
done < /dev/null > /dev/null 2>&1
|
||||
|
||||
exit 0
|
||||
|
6
opkg/CONTROL/prerm
Executable file
6
opkg/CONTROL/prerm
Executable file
@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
/mod/etc/init.d/S80mdnsd stop
|
||||
|
||||
exit 0
|
||||
|
BIN
opkg/sbin/mdnsd
Executable file
BIN
opkg/sbin/mdnsd
Executable file
Binary file not shown.
413
testmdnsd.c
413
testmdnsd.c
@ -25,6 +25,14 @@
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
@ -36,62 +44,381 @@
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include "mdns.h"
|
||||
#include "mdnsd.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
// create host entries
|
||||
char *hostname = "some-random-host.local";
|
||||
#define HOSTFILE "/tmp/hosts"
|
||||
|
||||
struct mdnsd *svr = mdnsd_start();
|
||||
if (svr == NULL) {
|
||||
printf("mdnsd_start() error\n");
|
||||
#if 0
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
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();
|
||||
}
|
||||
#endif
|
||||
|
||||
static void freehostents( struct hostent * h) {
|
||||
for (struct hostent *p = h; p->h_name; ++p) {
|
||||
free(p->h_name);
|
||||
free(p->h_addr_list);
|
||||
}
|
||||
free(h);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the mapping from hostname to in_addr_ip to the hosts block.
|
||||
* The return value is the pointer to the next entry after the added entry.
|
||||
* Case 1. The block is initially empty. Populate it with a loop like
|
||||
* for (p = hosts,i=0;; p = add_host(p, hostname[i], addr[i],++i);
|
||||
* Case 2. The block is in use. The added entry replaces the first one with
|
||||
* h_length == 0.
|
||||
*/
|
||||
static struct hostent * add_host(struct hostent * hosts, const char * hostname, struct in_addr ip) {
|
||||
struct hostent * p;
|
||||
|
||||
int newname = 1;
|
||||
for (p=hosts;p->h_name;++p) {
|
||||
if (p->h_length == 0 ||
|
||||
0 == (newname = strcasecmp(p->h_name, hostname)))
|
||||
break;
|
||||
}
|
||||
if (p->h_name) {
|
||||
if (0 != newname) {
|
||||
/* reusing an entry with a new name */
|
||||
free(p->h_name);
|
||||
p->h_name = strdup(hostname);
|
||||
}
|
||||
} else {
|
||||
/* new entry */
|
||||
p->h_name = strdup(hostname);
|
||||
(p+1)->h_name = 0;
|
||||
}
|
||||
p->h_aliases = 0;
|
||||
p->h_addrtype = AF_INET;
|
||||
p->h_length = sizeof(in_addr_t);
|
||||
p->h_addr_list = (char **) realloc(p->h_addr_list, sizeof(struct in_addr)+2*sizeof(struct in_addr*));
|
||||
p->h_addr_list[0] = (char *)(p->h_addr_list + 2);
|
||||
*(struct in_addr *)(p->h_addr_list[0]) = ip;
|
||||
p->h_addr_list[1] = NULL;
|
||||
return ++p;
|
||||
}
|
||||
|
||||
struct hostent * realloc_hosts(struct hostent * p, size_t n) {
|
||||
struct hostent * new = (struct hostent *) realloc(p,n*sizeof(struct hostent));
|
||||
if (!new) {
|
||||
fprintf(stderr, "Failed to allocate hostent: %s\n", strerror(errno));
|
||||
}
|
||||
return new;
|
||||
}
|
||||
|
||||
struct hostent * read_hosts(unsigned int extra) {
|
||||
FILE * hosts = fopen( HOSTFILE, "r");
|
||||
if (!hosts) {
|
||||
fprintf(stderr, "Failed to open hosts file: %s\n", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
size_t nhost = extra;
|
||||
while (0 <= fscanf(hosts, "%*[^\n]") && !ferror(hosts)) {
|
||||
if (0 <= fscanf(hosts,"%*c"))
|
||||
++nhost;
|
||||
}
|
||||
if (ferror(hosts) || -1 == fseek(hosts, 0L, SEEK_SET)) {
|
||||
fprintf(stderr, "Failed to read hosts file: %s\n", strerror(errno));
|
||||
fclose(hosts);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct hostent * hostents = (struct hostent *) realloc_hosts(NULL,++nhost);
|
||||
if (!hostents) {
|
||||
fclose(hosts);
|
||||
return NULL;
|
||||
} else {
|
||||
memset(hostents,0,nhost*sizeof(struct hostent));
|
||||
}
|
||||
|
||||
char ip[256];
|
||||
char name[256];
|
||||
char fmt[32];
|
||||
|
||||
/* a format for [the beginning of] a /etc/hosts line */
|
||||
int n = 0;
|
||||
if (snprintf( fmt, sizeof fmt - 1, "%%%zus %%%zus%%n%n", sizeof ip - 1, sizeof name - 1, &n) != n) {
|
||||
fprintf(stderr, "Format length %d inadequate\n", n);
|
||||
}
|
||||
/* and for further hostnames */
|
||||
char * nfmt = strchr(fmt,' ')+1;
|
||||
char * line = NULL;
|
||||
size_t linesz = 0;
|
||||
size_t nleft = nhost;
|
||||
hostents->h_name = 0;
|
||||
for (struct hostent * p = hostents;;) {
|
||||
int ret = getline( &line, &linesz, hosts);
|
||||
int pos = 0;
|
||||
if (ret == -1) {
|
||||
if (!feof(hosts)) {
|
||||
fprintf(stderr, "Failure reading hosts file: %s\n", strerror(errno));
|
||||
freehostents(hostents);
|
||||
hostents = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* skip initial space and any comment line */
|
||||
ret = sscanf( line, " %n", &pos );
|
||||
if (0 <= ret) {
|
||||
int n = 0;
|
||||
ret = sscanf( line+pos, "#%*[^\n]%n", &n);
|
||||
if (n > 0) continue;
|
||||
}
|
||||
|
||||
if (0 <= ret) {
|
||||
int n = 0;
|
||||
ret = sscanf( line+pos, fmt, ip, name, &n);
|
||||
// printf( "Read: %.255s\t%.32s\t%d\n", name, ip, ret);
|
||||
pos += n;
|
||||
}
|
||||
if (ret == 2) {
|
||||
struct in_addr it;
|
||||
it.s_addr = inet_addr(ip);
|
||||
do {
|
||||
char * dot = strrchr(name, '.');
|
||||
if (dot && 0 == strcasecmp(dot, ".local")) {
|
||||
struct hostent * pp = add_host(p, name, it);
|
||||
/* flag as expendable */
|
||||
p->h_length = 0;
|
||||
p = pp;
|
||||
} else {
|
||||
/* try to push down non-local names */
|
||||
struct hostent * pp = add_host(hostents, name, it);
|
||||
/* not pushed down -> appended */
|
||||
if (pp > p) p = pp;
|
||||
}
|
||||
|
||||
/* running out of space? try for more */
|
||||
if (--nleft < extra + 1) {
|
||||
size_t n = 2*nhost;
|
||||
struct hostent * new = (struct hostent *) realloc_hosts(hostents,n);
|
||||
if (!new) {
|
||||
free(line);
|
||||
fclose(hosts);
|
||||
free(hostents);
|
||||
return NULL;
|
||||
}
|
||||
/* zero the new space and adjust counts and pointers */
|
||||
memset(new+nhost,0,(n-nhost)*sizeof(struct hostent));
|
||||
nleft += n - nhost;
|
||||
nhost = n;
|
||||
p += new - hostents;
|
||||
hostents = new;
|
||||
}
|
||||
|
||||
/* allow for ip name [name ...] */
|
||||
int n = 0;
|
||||
ret = sscanf( line+pos, " %n", &n);
|
||||
pos += n;
|
||||
/* skip comment */
|
||||
if (0 <= ret) {
|
||||
n = 0;
|
||||
ret = sscanf( line+pos, "#%*[^\n]%n", &n);
|
||||
if (n > 0) break;
|
||||
}
|
||||
if (0 <= ret) {
|
||||
n = 0;
|
||||
ret = sscanf( line+pos, nfmt, name, &n);
|
||||
pos += n;
|
||||
}
|
||||
} while (ret == 1);
|
||||
p->h_name = 0;
|
||||
} else if (ret >= 0) {
|
||||
fprintf(stderr, "Unexpected format in hosts file; line was\n%s\n", line);
|
||||
}
|
||||
}
|
||||
free(line);
|
||||
fclose(hosts);
|
||||
return hostents;
|
||||
}
|
||||
|
||||
static int write_hosts(const struct hostent * hostents) {
|
||||
int ret = -1;
|
||||
FILE * hosts = fopen( HOSTFILE, "w");
|
||||
if (!hosts) {
|
||||
fprintf(stderr, "Failed to open hosts file: %s\n", strerror(errno));
|
||||
return ret;
|
||||
}
|
||||
for (const struct hostent * p = hostents;p->h_name;++p) {
|
||||
/* printf( "writing %.255s\n", p->h_name); */
|
||||
if (p->h_length > 0) {
|
||||
for (struct in_addr ** pa = (struct in_addr **)(p->h_addr_list); *pa; ++pa) {
|
||||
ret = fprintf( hosts, "%s\t%s\n", inet_ntoa(**pa), p->h_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(hosts);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void dump_host(const struct hostent * hostent) {
|
||||
printf( "Host: %.255s\t%.32s\t%d\n", hostent->h_name,
|
||||
inet_ntoa(*(struct in_addr *)(hostent->h_addr_list[0])),
|
||||
hostent->h_length);
|
||||
}
|
||||
|
||||
static void dump_hosts(const struct hostent * hostents) {
|
||||
for (const struct hostent * p = hostents;p->h_name;++p) {
|
||||
dump_host(p);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void handler_stop(int sig) {
|
||||
(void)sig;
|
||||
mdnsd_stop();
|
||||
#ifdef WIN32
|
||||
winsock_close();
|
||||
#endif
|
||||
exit(0);
|
||||
}
|
||||
|
||||
volatile static int running;
|
||||
|
||||
static void handler_restart(int sig) {
|
||||
/* a dummy handler so that sleep() will end early */
|
||||
(void)sig;
|
||||
if (running != 0)
|
||||
running = 2;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char hostname[0x100], ifname[0x120], fullname[0x108];
|
||||
|
||||
struct in_addr saddr;
|
||||
|
||||
if (gethostname(hostname, sizeof(hostname) - 1) == -1)
|
||||
{
|
||||
fprintf(stderr, "Couldn't retrieve humax hostname.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("mdnsd_start OK. press ENTER to add hostname & service\n");
|
||||
getchar();
|
||||
|
||||
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);
|
||||
int n = 0;
|
||||
if (snprintf(fullname, sizeof fullname - 1, "%s.local%n", hostname, &n) != n ||
|
||||
(n = 0, sprintf(ifname, "Humax Fox T2 (%s) Web Interface%n", hostname, &n) != n)) {
|
||||
fprintf( stderr, "Format length %d inadeqate\n", n);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
printf("added service and hostname. press ENTER to exit\n");
|
||||
getchar();
|
||||
running = 0;
|
||||
|
||||
mdnsd_stop(svr);
|
||||
signal(SIGINT, handler_stop);
|
||||
signal(SIGTERM, handler_stop);
|
||||
#if defined(SIGPIPE)
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
#if defined(SIGQUIT)
|
||||
signal(SIGQUIT, handler_stop);
|
||||
#endif
|
||||
#if defined(SIGHUP)
|
||||
signal(SIGHUP, handler_restart);
|
||||
#endif
|
||||
|
||||
|
||||
for (saddr.s_addr = 0;;sleep(61)) {
|
||||
struct hostent *hp = gethostbyname(hostname);
|
||||
char * ip_addr;
|
||||
|
||||
if (!hp || hp->h_length != sizeof(saddr.s_addr))
|
||||
{
|
||||
fprintf(stderr, "Couldn't retrieve humax IP address.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (running != 1 || saddr.s_addr != *(in_addr_t *)(hp->h_addr_list[0])) {
|
||||
if (running && (0 > mdnsd_stop())) {
|
||||
fprintf(stderr, "mdnsd_stop() error\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
saddr.s_addr = *(in_addr_t *)(hp->h_addr_list[0]);
|
||||
|
||||
ip_addr = inet_ntoa(saddr);
|
||||
|
||||
printf("Hostname: %s (%s)\n", hostname, ip_addr);
|
||||
|
||||
if (mdnsd_start(fullname, ip_addr) < 0) {
|
||||
fprintf(stderr, "mdnsd_start() error\n");
|
||||
/* may just have no interface */
|
||||
continue;
|
||||
}
|
||||
running = 1;
|
||||
|
||||
/* service must have FQDN */
|
||||
if (0 <= mdnsd_register_service(
|
||||
ifname, "_http._tcp.local", 80,
|
||||
fullname, txt))
|
||||
printf("Registered name.\n");
|
||||
}
|
||||
|
||||
int numserv = 0;
|
||||
struct mdns_service_info * svcinfo;
|
||||
|
||||
if (0 <= mdnsd_discover_service("_http._tcp.local", 5000, &svcinfo, &numserv)) {
|
||||
|
||||
/* allow an extra entry for own host */
|
||||
struct hostent * hosts = read_hosts(numserv+1);
|
||||
if (!hosts) {
|
||||
fprintf(stderr,"null hosts\n");
|
||||
return 1;
|
||||
}
|
||||
//dump_hosts(hosts);
|
||||
/* recognise own .local hostname */
|
||||
struct hostent * p = add_host(hosts, fullname, saddr);
|
||||
for (int i = 0; i < numserv; ++i) {
|
||||
struct in_addr it;
|
||||
it.s_addr = svcinfo[i].ipaddr;
|
||||
printf("Host %d: %s (%s)\n", i, svcinfo[i].hostname, inet_ntoa(it));
|
||||
p = add_host(p, svcinfo[i].hostname, it);
|
||||
}
|
||||
/* p->h_name = 0; */
|
||||
write_hosts(hosts);
|
||||
freehostents(hosts);
|
||||
}
|
||||
}
|
||||
|
||||
if (running && (0 > mdnsd_stop())) {
|
||||
fprintf(stderr,"mdnsd_stop() error\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user