diff --git a/alpine/Dockerfile b/alpine/Dockerfile index 493746795..244755c66 100644 --- a/alpine/Dockerfile +++ b/alpine/Dockerfile @@ -43,9 +43,6 @@ COPY packages/transfused/transfused /sbin/ COPY packages/transfused/etc /etc/ COPY packages/tap-vsockd/tap-vsockd /sbin/ COPY packages/tap-vsockd/etc /etc/ -COPY packages/llmnrd/llmnrd /sbin/ -COPY packages/llmnrd/etc /etc/ -COPY packages/llmnrd/llmnrd.tar.gz /usr/share/src/ COPY packages/docker/bin/* /usr/bin/ COPY packages/docker/etc /etc/ COPY packages/diagnostics/diagnostics /usr/bin/ @@ -104,7 +101,6 @@ RUN \ rc-update add docker default && \ rc-update add proxy default && \ rc-update add transfused default && \ - rc-update add llmnrd default && \ rc-update add automount boot && \ rc-update add diagnostics default && \ rc-update add binfmt_misc default && \ diff --git a/alpine/packages/llmnrd/.gitignore b/alpine/packages/llmnrd/.gitignore deleted file mode 100644 index b115d4acd..000000000 --- a/alpine/packages/llmnrd/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/llmnrd -/llmnrd.tar.gz diff --git a/alpine/packages/llmnrd/Dockerfile b/alpine/packages/llmnrd/Dockerfile deleted file mode 100644 index 3e8d0df1c..000000000 --- a/alpine/packages/llmnrd/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM alpine:3.4 - -RUN apk update && apk upgrade && apk add build-base linux-headers - -RUN mkdir -p /llmnrd - -COPY src /llmnrd/ -RUN tar czvf /llmnrd.tar.gz llmnrd - -WORKDIR /llmnrd -RUN make diff --git a/alpine/packages/llmnrd/Makefile b/alpine/packages/llmnrd/Makefile deleted file mode 100644 index bec55e542..000000000 --- a/alpine/packages/llmnrd/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -all: llmnrd - -llmnrd: Dockerfile src/* - docker build -t llmnrd:build . - docker run --rm llmnrd:build cat /llmnrd.tar.gz > llmnrd.tar.gz - docker run --rm llmnrd:build cat /llmnrd/llmnrd > llmnrd - chmod 755 llmnrd - -clean: - rm -f llmnrd llmnrd.tar.gz - docker images -q llmnrd:build | xargs docker rmi -f || true diff --git a/alpine/packages/llmnrd/etc/init.d/llmnrd b/alpine/packages/llmnrd/etc/init.d/llmnrd deleted file mode 100755 index 8efec26c9..000000000 --- a/alpine/packages/llmnrd/etc/init.d/llmnrd +++ /dev/null @@ -1,42 +0,0 @@ -#!/sbin/openrc-run - -description="LLMNR Daemon" - -depend() -{ - need net - after firewall -} - -start() -{ - [ ! -d /sys/bus/vmbus ] && exit 0 - - ebegin "Starting LLMNR Daemon" - - [ -n "${PIDFILE}" ] || PIDFILE=/var/run/llmnrd.pid - - # always serve as 'docker' - export HOSTNAME=docker - - start-stop-daemon --start --quiet \ - --background \ - --exec /sbin/llmnrd \ - --make-pidfile --pidfile ${PIDFILE} \ - -- -H ${HOSTNAME} -p 5355 -6 - - eend $? "Failed to start LLMNR Dameon" -} - -stop() -{ - [ ! -d /sys/bus/vmbus ] && exit 0 - - ebegin "Stopping LLMNR Daemon" - - [ -n "${PIDFILE}" ] || PIDFILE=/var/run/llmnrd.pid - - start-stop-daemon --stop --quiet --pidfile ${PIDFILE} - - eend $? "Failed to stop LLMNR Daemon" -} diff --git a/alpine/packages/llmnrd/src/Makefile b/alpine/packages/llmnrd/src/Makefile deleted file mode 100644 index a80aa7b4f..000000000 --- a/alpine/packages/llmnrd/src/Makefile +++ /dev/null @@ -1,74 +0,0 @@ -# Makefile for llmnrd -# -# Copyright (C) 2014-2015 Tobias Klauser - -VERSION = 0.1-rc1 - -# llmnrd binary -D_P = llmnrd -D_OBJS = llmnr.o iface.o socket.o util.o llmnrd.o -D_LIBS = -lpthread - -# llmnr-query binary -Q_P = llmnr-query -Q_OBJS = util.o llmnr-query.o -Q_LIBS = - -CC = $(CROSS_COMPILE)gcc -INSTALL = install - -CFLAGS ?= -W -Wall -O2 -LDFLAGS ?= - -ifeq ($(shell git rev-parse > /dev/null 2>&1; echo $$?), 0) - GIT_VERSION = "(git id $(shell git describe --always))" -else - GIT_VERSION = -endif - -CFLAGS += -DVERSION_STRING=\"v$(VERSION)\" -DGIT_VERSION=\"$(GIT_VERSION)\" - -ifeq ($(DEBUG), 1) - CFLAGS += -g -DDEBUG -endif - -Q ?= @ -CCQ = $(Q)echo " CC $<" && $(CC) -LDQ = $(Q)echo " LD $@" && $(CC) - -prefix ?= /usr/local - -BINDIR = $(prefix)/bin -SBINDIR = $(prefix)/sbin -DESTDIR = - -all: $(D_P) $(Q_P) - -$(D_P): $(D_OBJS) - $(LDQ) $(LDFLAGS) -o $@ $(D_OBJS) $(D_LIBS) - -$(Q_P): $(Q_OBJS) - $(LDQ) $(LDFLAGS) -o $@ $(Q_OBJS) $(Q_LIBS) - -%.o: %.c %.h - $(CCQ) $(CFLAGS) -o $@ -c $< - -%.o: %.c - $(CCQ) $(CFLAGS) -o $@ -c $< - -install_$(D_P): $(D_P) - @echo " INSTALL $(D_P)" - @$(INSTALL) -d -m 755 $(DESTDIR)$(SBINDIR) - @$(INSTALL) -m 755 $(D_P) $(DESTDIR)$(SBINDIR)/$(D_P) - -install_$(Q_P): $(Q_P) - @echo " INSTALL $(Q_P)" - @$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR) - @$(INSTALL) -m 755 $(Q_P) $(DESTDIR)$(BINDIR)/$(Q_P) - -install: install_$(D_P) install_$(Q_P) - -clean: - @echo " CLEAN" - @rm -f $(D_OBJS) $(D_P) - @rm -f $(Q_OBJS) $(Q_P) diff --git a/alpine/packages/llmnrd/src/README b/alpine/packages/llmnrd/src/README deleted file mode 100644 index 3d563395f..000000000 --- a/alpine/packages/llmnrd/src/README +++ /dev/null @@ -1,66 +0,0 @@ -llmnrd - Link-Local Multicast Resolution Daemon -=============================================== - -llmnrd is a daemon implementing the Link-Local Multicast Name Resolution (LLMNR) -protocol according to RFC 4795. It currently only supports Linux, as it uses the -netlink kernel interface. - -llmnrd will respond to name resolution queries sent by Windows clients in -networks where no DNS server is available. It supports both IPv4 and IPv6. - -Installation ------------- - -To build and install llmnrd use the following commands: - - $ make - $ sudo make install - -By default, the llmnrd binary will be installed to /usr/local/sbin. To install -the binary to a different installation path, use: - - $ make - $ sudo make prefix= install - -Cross-Compilation ------------------ - -To cross-compile llmnrd for a different architecture, use the CROSS_COMPILE make -variable. To e.g. build it using the arm-linux-gnueabihf toolchain use: - - $ make CROSS_COMPILE=arm-linux-gnueabihf- - -When cross-compiling, you usually don't want to install the generated binary to -your root filesystem, but to the sysroot of a cross-compiled system. Use the -DESTDIR variable to change the installation destination path, e.g. - - $ make DESTDIR=$HOME/sysroot/ prefix=/usr install - -License -------- - -llmnrd is free software: you can redistribute it and/or modify it under the -terms of the GNU General Public License as published by the Free Software -Foundation, version 2 of the License. - -llmnrd is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A -PARTICULAR PURPOSE. See the GNU General Public License for more details. - -Author ------- - -llmnrd is authored and maintained by Tobias Klauser - -References ----------- - -RFC 4795 - https://tools.ietf.org/html/rfc4795 - -Microsoft TechNet article about LLMNR - https://technet.microsoft.com/en-us/library/bb878128.aspx - -xllmnrd: An IPv6-only LLMNR responder daemon - http://www.vx68k.org/xllmnrd - https://bitbucket.org/kazssym/xllmnrd/ diff --git a/alpine/packages/llmnrd/src/compiler.h b/alpine/packages/llmnrd/src/compiler.h deleted file mode 100644 index 3559050ca..000000000 --- a/alpine/packages/llmnrd/src/compiler.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2015 Tobias Klauser - * - * This file is part of llmnrd. - * - * llmnrd is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * - * llmnrd is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with llmnrd. If not, see . - */ - -#ifndef COMPILER_H -#define COMPILER_H - -#ifdef __GNUC__ -# define __noreturn __attribute__((noreturn)) -# define __warn_unused_result __attribute__((warn_unused_result)) -# define __packed __attribute__((packed)) -# define __unused __attribute__((unused)) -# ifndef offsetof -# define offsetof(a, b) __builtin_offsetof(a, b) -# endif -#else -# define __noreturn -# define __packed -# define __unused -#endif - -#ifndef offsetof -# define offsetof(type, member) ((size_t) &((type *)0)->member) -#endif - -#ifndef container_of -# define container_of(ptr, type, member) ({ \ - const typeof(((type *)0)->member) *__mptr = (ptr); \ - (type *)((char *)__mptr - offsetof(type, member));}) -#endif - -#endif /* COMPILER_H */ diff --git a/alpine/packages/llmnrd/src/err.h b/alpine/packages/llmnrd/src/err.h deleted file mode 100644 index 6a1d856e3..000000000 --- a/alpine/packages/llmnrd/src/err.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2015 Tobias Klauser - * - * This file is part of llmnrd. - * - * llmnrd is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * - * llmnrd is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with llmnrd. If not, see . - */ - -#ifndef ERR_H -#define ERR_H - -static inline void *ERR_PTR(long err) -{ - return (void *)err; -} - -static inline long PTR_ERR(const void *ptr) -{ - return (long)ptr; -} - -#endif /* ERR_H */ diff --git a/alpine/packages/llmnrd/src/iface.c b/alpine/packages/llmnrd/src/iface.c deleted file mode 100644 index 8c77c617c..000000000 --- a/alpine/packages/llmnrd/src/iface.c +++ /dev/null @@ -1,395 +0,0 @@ -/* - * Copyright (C) 2015 Tobias Klauser - * - * This file is part of llmnrd. - * - * llmnrd is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * - * llmnrd is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with llmnrd. If not, see . - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "err.h" -#include "list.h" -#include "log.h" -#include "socket.h" -#include "util.h" - -#include "iface.h" - -static bool iface_running = true; -static pthread_t iface_thread; -static iface_event_handler_t iface_event_handler; - -struct iface_record { - struct list_head list; - unsigned int index; - struct sockaddr_storage *addrs; - size_t size; -}; - -static struct list_head iface_list_head; -static pthread_mutex_t iface_list_mutex; - -size_t iface_addr_lookup(unsigned int ifindex, unsigned char family, - struct sockaddr_storage *addrs, size_t addrs_size) -{ - struct iface_record *rec; - size_t n = 0; - - if (!addrs) - return 0; - - pthread_mutex_lock(&iface_list_mutex); - - list_for_each_entry(rec, &iface_list_head, list) { - if (rec->index == ifindex) { - size_t i; - - for (i = 0; i < rec->size && n < addrs_size; i++) { - if (family == AF_UNSPEC || family == rec->addrs[i].ss_family) { - memcpy(&addrs[n], &rec->addrs[i], sizeof(addrs[n])); - n++; - } - } - break; - } - } - - pthread_mutex_unlock(&iface_list_mutex); - - return n; -} - -static bool iface_record_addr_eq(const struct sockaddr_storage *addr1, - const struct sockaddr_storage *addr2) -{ - int family = addr1->ss_family; - - if (family != addr2->ss_family) - return false; - - if (family == AF_INET) { - const struct sockaddr_in *sin1 = (const struct sockaddr_in *)addr1; - const struct sockaddr_in *sin2 = (const struct sockaddr_in *)addr2; - - return memcmp(&sin1->sin_addr, &sin2->sin_addr, sizeof(sin1->sin_addr)) == 0; - } else if (family == AF_INET6) { - const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)addr1; - const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)addr2; - - return memcmp(&sin1->sin6_addr, &sin2->sin6_addr, sizeof(sin1->sin6_addr)) == 0; - } else { - /* This should never happen */ - log_warn("Unsupported address family: %d\n", family); - return memcmp(addr1, addr2, sizeof(*addr1)); - } -} - -static void iface_record_addr_add(struct iface_record *rec, struct sockaddr_storage *addr) -{ - size_t i; - struct sockaddr_storage *addrs = rec->addrs; - - for (i = 0; i < rec->size; i++) { - /* Address already in record? */ - if (iface_record_addr_eq(&addrs[i], addr)) - return; - } - - addrs = xrealloc(rec->addrs, (rec->size + 1) * sizeof(*addr)); - memcpy(&addrs[rec->size], addr, sizeof(*addr)); - rec->addrs = addrs; - rec->size++; -} - -static void iface_record_addr_del(struct iface_record *rec, struct sockaddr_storage *addr) -{ - if (rec->size > 1) { - size_t i, j = 0; - struct sockaddr_storage *addrs = xmalloc((rec->size - 1) * sizeof(*addr)); - - for (i = 0; i < rec->size; i++) { - if (!iface_record_addr_eq(&rec->addrs[i], addr)) { - memcpy(&addrs[j], &rec->addrs[i], sizeof(addrs[j])); - j++; - } - } - - if (j == i - 1) { - free(rec->addrs); - rec->addrs = addrs; - rec->size--; - } else { - char as[INET6_ADDRSTRLEN]; - inet_ntop(addr->ss_family, addr + sizeof(addr->ss_family), as, sizeof(as)); - log_err("Address %s to delete not found in records\n", as); - } - } else if (rec->size == 1) { - free(rec->addrs); - rec->addrs = NULL; - rec->size = 0; - } -} - -static inline void fill_sockaddr_storage(struct sockaddr_storage *sst, - unsigned char family, const void *addr) -{ - sst->ss_family = family; - if (family == AF_INET) { - struct sockaddr_in *sin = (struct sockaddr_in *)sst; - memcpy(&sin->sin_addr, addr, sizeof(sin->sin_addr)); - } else if (family == AF_INET6) { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sst; - memcpy(&sin6->sin6_addr, addr, sizeof(sin6->sin6_addr)); - } -} - -static void iface_addr_add(unsigned int index, unsigned char family, const void *addr) -{ - struct iface_record *rec; - struct sockaddr_storage sst; - - fill_sockaddr_storage(&sst, family, addr); - - pthread_mutex_lock(&iface_list_mutex); - - list_for_each_entry(rec, &iface_list_head, list) - if (rec->index == index) - goto add; - - rec = xzalloc(sizeof(*rec)); - INIT_LIST_HEAD(&rec->list); - rec->index = index; - - list_add_tail(&rec->list, &iface_list_head); -add: - iface_record_addr_add(rec, &sst); - pthread_mutex_unlock(&iface_list_mutex); -} - -static void iface_addr_del(unsigned int index, unsigned char family, const void *addr) -{ - struct iface_record *rec; - struct sockaddr_storage sst; - - fill_sockaddr_storage(&sst, family, addr); - - pthread_mutex_lock(&iface_list_mutex); - - list_for_each_entry(rec, &iface_list_head, list) { - if (rec->index == index) { - iface_record_addr_del(rec, &sst); - break; - } - } - - pthread_mutex_unlock(&iface_list_mutex); -} - -static void iface_nlmsg_change_link(const struct nlmsghdr *nlh __unused) -{ - /* TODO */ -} - -static void iface_nlmsg_change_addr(const struct nlmsghdr *nlh) -{ - struct ifaddrmsg *ifa = NLMSG_DATA(nlh); - struct rtattr *rta; - size_t rtalen = nlh->nlmsg_len - NLMSG_SPACE(sizeof(*ifa)); - unsigned char family = ifa->ifa_family; - unsigned int index = ifa->ifa_index; - char ifname[IF_NAMESIZE]; - - /* don't report temporary addresses */ - if ((ifa->ifa_flags & (IFA_F_TEMPORARY | IFA_F_TENTATIVE)) != 0) - return; - - if_indextoname(index, ifname); - - rta = (struct rtattr *)((const uint8_t *)nlh + NLMSG_SPACE(sizeof(*ifa))); - for ( ; RTA_OK(rta, rtalen); rta = RTA_NEXT(rta, rtalen)) { - char addr[INET6_ADDRSTRLEN]; - enum iface_event_type type; - - if (rta->rta_type != IFA_ADDRESS) - continue; - - if (!inet_ntop(family, RTA_DATA(rta), addr, sizeof(addr))) - strncpy(addr, "", sizeof(addr) - 1); - - if (nlh->nlmsg_type == RTM_NEWADDR) { - iface_addr_add(index, family, RTA_DATA(rta)); - type = IFACE_ADD; - } else if (nlh->nlmsg_type == RTM_DELADDR) { - iface_addr_del(index, family, RTA_DATA(rta)); - type = IFACE_DEL; - } else { - /* This case shouldn't occur */ - continue; - } - - if (iface_event_handler) - (*iface_event_handler)(type, family, index); - - log_info("%s IPv%c address %s on interface %s\n", - type == IFACE_ADD ? "Added" : "Deleted", - family == AF_INET ? '4' : '6', addr, ifname); - } -} - -static int iface_nlmsg_process(const struct nlmsghdr *nlh, size_t len) -{ - for ( ; len > 0; nlh = NLMSG_NEXT(nlh, len)) { - struct nlmsgerr *err; - - if (!NLMSG_OK(nlh, len)) { - log_err("netlink message truncated\n"); - return -1; - } - - switch (nlh->nlmsg_type) { - case RTM_NEWADDR: - case RTM_DELADDR: - iface_nlmsg_change_addr(nlh); - break; - case RTM_NEWLINK: - case RTM_DELLINK: - iface_nlmsg_change_link(nlh); - break; - case NLMSG_ERROR: - err = NLMSG_DATA(nlh); - log_err("netlink error: %s\n", strerror(-(err->error))); - break; - case NLMSG_DONE: - if (!NLMSG_OK(nlh, len)) { - log_err("netlink message truncated\n"); - return -1; - } else - return 0; - default: - /* log_warn("Unknown netlink message type: 0x%x\n", nlh->nlmsg_type); */ - break; - } - } - - return 0; -} - -static int iface_rtnl_enumerate(int sock, uint16_t type, unsigned char family) -{ - struct { - struct nlmsghdr n; - struct rtgenmsg r; - } req; - ssize_t recvlen; - uint8_t pktbuf[8192]; - - memset(&req, 0, sizeof(req)); - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.r)); - req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; - req.n.nlmsg_type = type; - req.r.rtgen_family = family; - - if (send(sock, &req, req.n.nlmsg_len, 0) < 0) { - log_err("Failed to send netlink enumeration message: %s\n", strerror(errno)); - return -1; - } - - if ((recvlen = recv(sock, pktbuf, sizeof(pktbuf), 0)) < 0) { - if (errno != EINTR) - log_err("Failed to receive netlink message: %s\n", strerror(errno)); - return -1; - } - - return iface_nlmsg_process((const struct nlmsghdr *)pktbuf, recvlen); -} - -void iface_register_event_handler(iface_event_handler_t event_handler) -{ - iface_event_handler = event_handler; -} - -int iface_run(void) -{ - int ret = -1; - int sock; - - INIT_LIST_HEAD(&iface_list_head); - if (pthread_mutex_init(&iface_list_mutex, NULL) != 0) { - log_err("Failed to initialize interface list mutex\n"); - return -1; - } - - sock = socket_open_rtnl(); - if (sock < 0) - return -1; - - /* send RTM_GETADDR request to initially populate the interface list */ - if (iface_rtnl_enumerate(sock, RTM_GETADDR, AF_INET) < 0) - return -1; - if (iface_rtnl_enumerate(sock, RTM_GETADDR, AF_INET6) < 0) - return -1; - - while (iface_running) { - ssize_t recvlen; - uint8_t pktbuf[8192]; - - if ((recvlen = recv(sock, pktbuf, sizeof(pktbuf), 0)) < 0) { - if (errno != EINTR) - log_err("Failed to receive netlink message: %s\n", strerror(errno)); - goto out; - } - - if (iface_nlmsg_process((const struct nlmsghdr *)pktbuf, recvlen) < 0) - log_warn("Error processing netlink message\n"); - } - - pthread_mutex_destroy(&iface_list_mutex); - ret = 0; -out: - close(sock); - return ret; -} - -static void* iface_run_wrapper(void *data __unused) -{ - return ERR_PTR(iface_run()); -} - -int iface_start_thread(void) -{ - if (pthread_create(&iface_thread, NULL, iface_run_wrapper, NULL) < 0) { - log_err("Failed to start interface monitoring thread\n"); - return -1; - } - - return 0; -} - -void iface_stop(void) -{ - iface_running = false; -} diff --git a/alpine/packages/llmnrd/src/iface.h b/alpine/packages/llmnrd/src/iface.h deleted file mode 100644 index 47321d513..000000000 --- a/alpine/packages/llmnrd/src/iface.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2015 Tobias Klauser - * - * This file is part of llmnrd. - * - * llmnrd is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * - * llmnrd is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with llmnrd. If not, see . - */ - -#ifndef IFACE_H -#define IFACE_H - -#include - -enum iface_event_type { - IFACE_ADD, - IFACE_DEL, -}; - -typedef void (*iface_event_handler_t)(enum iface_event_type, unsigned char af, - unsigned int ifindex); - -void iface_register_event_handler(iface_event_handler_t event_handler); -int iface_start_thread(void); -void iface_stop(void); - -size_t iface_addr_lookup(unsigned int ifindex, unsigned char family, - struct sockaddr_storage *addrs, size_t addrs_size); - -#endif /* IFACE_H */ diff --git a/alpine/packages/llmnrd/src/list.h b/alpine/packages/llmnrd/src/list.h deleted file mode 100644 index cd2bde98c..000000000 --- a/alpine/packages/llmnrd/src/list.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Simple doubly linked list, based on the Linux kernel linked list. - * - * Copyright (C) 2015 Tobias Klauser - * - * This file is part of llmnrd. - * - * llmnrd is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * - * llmnrd is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with llmnrd. If not, see . - */ - -#ifndef LIST_H -#define LIST_H - -#include - -#include "compiler.h" - -struct list_head { - struct list_head *next, *prev; -}; - -static inline void INIT_LIST_HEAD(struct list_head *list) -{ - list->next = list; - list->prev = list; -} - -static inline void __list_add(struct list_head *obj, - struct list_head *prev, - struct list_head *next) -{ - prev->next = obj; - obj->prev = prev; - obj->next = next; - next->prev = obj; -} - -static inline void list_add_tail(struct list_head *obj, struct list_head *head) -{ - __list_add(obj, head->prev, head); -} - -static inline void list_add_head(struct list_head *obj, struct list_head *head) -{ - __list_add(obj, head, head->next); -} - -static inline void list_del(struct list_head *obj) -{ - obj->next->prev = obj->prev; - obj->prev->next = obj->next; -} - -static inline bool list_empty(struct list_head *head) -{ - return head->next == head; -} - -#define list_entry(ptr, type, member) container_of(ptr, type, member) - -#define list_for_each_entry(pos, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member); \ - &(pos)->member != (head); \ - (pos) = list_entry((pos)->member.next, typeof(*(pos)), member)) - -#define list_for_each_entry_safe(pos, n, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &(pos)->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -#endif /* LIST_H */ diff --git a/alpine/packages/llmnrd/src/llmnr-packet.h b/alpine/packages/llmnrd/src/llmnr-packet.h deleted file mode 100644 index 8b26bb92c..000000000 --- a/alpine/packages/llmnrd/src/llmnr-packet.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * LLMNR (RFC 4705) packet format definitions - * - * Copyright (C) 2015 Tobias Klauser - * - * This file is part of llmnrd. - * - * llmnrd is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * - * llmnrd is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with llmnrd. If not, see . - */ - -#ifndef LLMNR_PACKET_H -#define LLMNR_PACKET_H - -#include - -#include "compiler.h" - -#define LLMNR_IPV4_MCAST_ADDR "224.0.0.252" -#define LLMNR_IPV6_MCAST_ADDR "ff02:0:0:0:0:0:1:3" - -#define LLMNR_UDP_PORT 5355 - -/* - * LLMNR packet header (RFC 4795, section 2.1.1) - */ -struct llmnr_hdr { - uint16_t id; - uint16_t flags; -#define LLMNR_F_QR 0x8000 -#define LLMNR_F_OPCODE 0x7800 -#define LLMNR_F_C 0x0400 -#define LLMNR_F_TC 0x0200 -#define LLMNR_F_T 0x0100 -#define LLMNR_F_RCODE 0x000f - uint16_t qdcount; - uint16_t ancount; - uint16_t nscount; - uint16_t arcount; -} __packed; - -/* Maximum label length according to RFC 1035 */ -#define LLMNR_LABEL_MAX_SIZE 63 - -/* TYPE values according to RFC1035, section 3.2.2 */ -#define LLMNR_TYPE_A 1 -#define LLMNR_TYPE_NS 2 -#define LLMNR_TYPE_CNAME 5 -#define LLMNR_TYPE_SOA 6 -#define LLMNR_TYPE_PTR 12 -#define LLMNR_TYPE_HINFO 13 -#define LLMNR_TYPE_MINFO 14 -#define LLMNR_TYPE_MX 15 -#define LLMNR_TYPE_TXT 16 -#define LLMNR_TYPE_AAAA 28 /* RFC 3596 */ - -/* QTYPE values according to RFC1035, section 3.2.3 */ -#define LLMNR_QTYPE_A LLMNR_TYPE_A -#define LLMNR_QTYPE_AAAA LLMNR_TYPE_AAAA -#define LLMNR_QTYPE_ANY 255 - -/* CLASS values */ -#define LLMNR_CLASS_IN 1 - -/* QCLASS values */ -#define LLMNR_QCLASS_IN LLMNR_CLASS_IN - -/* Default RR TTL in seconds (RFC 4795, section 2.8) */ -#define LLMNR_TTL_DEFAULT 30 - -#endif /* LLMNR_PACKET_H */ diff --git a/alpine/packages/llmnrd/src/llmnr-query.c b/alpine/packages/llmnrd/src/llmnr-query.c deleted file mode 100644 index 303961df2..000000000 --- a/alpine/packages/llmnrd/src/llmnr-query.c +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Simple LLMNR query command. - * - * Copyright (C) 2015 Tobias Klauser - * - * This file is part of llmnrd. - * - * llmnrd is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * - * llmnrd is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with llmnrd. If not, see . - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "compiler.h" -#include "llmnr-packet.h" -#include "log.h" -#include "pkt.h" - -static const char *short_ops = "c:i:I:t:T:6hV"; -static const struct option long_opts[] = { - { "count", required_argument, NULL, 'c' }, - { "interval", required_argument, NULL, 'i' }, - { "interface", required_argument, NULL, 'I' }, - { "timeout", required_argument, NULL, 't' }, - { "type", required_argument, NULL, 'T' }, - { "ipv6", no_argument, NULL, '6' }, - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'V' }, - { NULL, 0, NULL, 0 }, -}; - -static void __noreturn usage_and_exit(int status) -{ - fprintf(stdout, "Usage: llmnr-query [OPTIONS...] NAME\n" - "Options:\n" - " -c, --count NUM number of queries to send (default: 1)\n" - " -i, --interval NUM interval between queries in ms (default: 500)\n" - " -I, --interface NAME send multicast over specified interface\n" - " -t, --timeout NUM time to wait for reply in ms (default: 1000)\n" - " -T, --type TYPE set query type; must be one of A, AAAA, ANY (default: A)\n" - " -6, --ipv6 send queries over IPv6\n" - " -h, --help show this help and exit\n" - " -V, --version show version information and exit\n"); - exit(status); -} - -static void __noreturn version_and_exit(void) -{ - fprintf(stdout, "llmnr-query %s %s\n" - "Copyright (C) 2015 Tobias Klauser \n" - "Licensed under the GNU General Public License, version 2\n", - VERSION_STRING, GIT_VERSION); - exit(EXIT_SUCCESS); -} - -static const char *query_type(uint16_t qtype) -{ - switch (qtype) { - case LLMNR_QTYPE_A: - return "A"; - case LLMNR_QTYPE_AAAA: - return "AAAA"; - case LLMNR_QTYPE_ANY: - return "ANY"; - default: - return ""; - } -} - -int main(int argc, char **argv) -{ - int c, sock; - const char *query_name, *iface = NULL; - size_t query_name_len; - unsigned long i, count = 1, interval_ms = 500, timeout_ms = 1000; - uint16_t qtype = LLMNR_QTYPE_A; - bool ipv6 = false; - struct pkt *p; - - while ((c = getopt_long(argc, argv, short_ops, long_opts, NULL)) != -1) { - switch (c) { - case 'c': - count = strtoul(optarg, NULL, 0); - break; - case 'i': - interval_ms = strtoul(optarg, NULL, 0); - break; - case 'I': - iface = xstrdup(optarg); - break; - case 't': - timeout_ms = strtoul(optarg, NULL, 0); - break; - case 'T': - if (xstreq("A", optarg)) - qtype = LLMNR_QTYPE_A; - else if (xstreq("AAAA", optarg)) - qtype = LLMNR_QTYPE_AAAA; - else if (xstreq("ANY", optarg)) - qtype = LLMNR_QTYPE_ANY; - else { - printf("Invalid query type: %s\n", optarg); - usage_and_exit(EXIT_FAILURE); - } - break; - case '6': - ipv6 = true; - break; - case 'V': - version_and_exit(); - case 'h': - usage_and_exit(EXIT_SUCCESS); - default: - usage_and_exit(EXIT_FAILURE); - } - } - - if (optind >= argc) - usage_and_exit(EXIT_FAILURE); - - query_name = argv[optind]; - query_name_len = strlen(query_name); - if (query_name_len > UINT8_MAX) { - log_err("Query name too long\n"); - return -1; - } - - sock = socket(ipv6 ? AF_INET6 : AF_INET, SOCK_DGRAM, 0); - if (sock < 0) { - log_err("Failed to open UDP socket: %s\n", strerror(errno)); - return -1; - } - - if (iface != NULL) { - unsigned int ifindex = if_nametoindex(iface); - - if (ifindex == 0 && errno != 0) { - log_err("Could not get interface %s: %s\n", iface, strerror(errno)); - goto err; - } - - if (ipv6) { - if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex)) < 0) { - log_err("Failed to set interface '%s' for IPv6 multicast socket: %s\n", - iface, strerror(errno)); - goto err; - } - } else { - struct ip_mreqn mreq; - - memset(&mreq, 0, sizeof(mreq)); - mreq.imr_ifindex = ifindex; - - if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &mreq, sizeof(mreq)) < 0) { - log_err("Failed to set interface '%s' for IPv4 multicast socket: %s\n", - iface, strerror(errno)); - goto err; - } - } - } - - p = pkt_alloc(128); - - log_info("LLMNR query: %s IN %s\n", query_name, query_type(qtype)); - - for (i = 0; i < count; i++) { - struct llmnr_hdr *hdr; - struct sockaddr_storage sst; - size_t query_pkt_len; - fd_set rfds; - struct timeval tv; - int ret; - - hdr = (struct llmnr_hdr *)pkt_put(p, sizeof(*hdr)); - hdr->id = htons(i % UINT16_MAX); - hdr->flags = 0; - hdr->qdcount = htons(1); - hdr->ancount = 0; - hdr->nscount = 0; - hdr->arcount = 0; - - pkt_put_u8(p, (uint8_t)query_name_len); - memcpy(pkt_put(p, query_name_len), query_name, query_name_len); - pkt_put_u8(p, 0); - - pkt_put_u16(p, htons(qtype)); - pkt_put_u16(p, htons(LLMNR_QCLASS_IN)); - - memset(&sst, 0, sizeof(sst)); - if (ipv6) { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&sst; - - sin6->sin6_family = AF_INET6; - sin6->sin6_port = htons(LLMNR_UDP_PORT); - if (inet_pton(AF_INET6, LLMNR_IPV6_MCAST_ADDR, &sin6->sin6_addr) != 1) { - log_err("Failed to convert IPv6 address: %s\n", strerror(errno)); - break; - } - } else { - struct sockaddr_in *sin = (struct sockaddr_in *)&sst; - - sin->sin_family = AF_INET; - sin->sin_port = htons(LLMNR_UDP_PORT); - if (inet_pton(AF_INET, LLMNR_IPV4_MCAST_ADDR, &sin->sin_addr) != 1) { - log_err("Failed to convert IPv4 address: %s\n", strerror(errno)); - break; - } - } - - query_pkt_len = pkt_len(p) - sizeof(*hdr); - - if (sendto(sock, p->data, pkt_len(p), 0, (struct sockaddr *)&sst, sizeof(sst)) < 0) { - log_err("Failed to send UDP packet: %s\n", strerror(errno)); - break; - } - - FD_ZERO(&rfds); - FD_SET(sock, &rfds); - - /* wait up to one second for a response */ - tv.tv_sec = timeout_ms / 1000; - tv.tv_usec = (timeout_ms % 1000) * 1000; - - ret = select(sock + 1, &rfds, NULL, NULL, &tv); - if (ret < 0) { - log_err("Failed to select() on socket: %s\n", strerror(errno)); - break; - } else if (ret) { - uint16_t j, ancount; - - pkt_reset(p); - if (recv(sock, p->data, p->size, 0) < 0) { - log_err("Failed to receive from socket: %s\n", strerror(errno)); - break; - } - - hdr = (struct llmnr_hdr *)pkt_put(p, sizeof(*hdr)); - ancount = htons(hdr->ancount); - - if (ancount == 0) { - log_info("LLMNR response: no answer records returned\n"); - continue; - } - - /* skip the original query */ - pkt_put(p, query_pkt_len); - - for (j = 0; j < ancount; ++j) { - uint8_t nl = *pkt_put(p, 1); - char addr[INET6_ADDRSTRLEN]; - uint16_t type, clss, addr_size; - uint32_t ttl; - char *name; - int af; - - /* compression? */ - if (nl & 0xC0) { - uint16_t ptr = (nl & 0x3F) << 8 | *pkt_put(p, 1); - name = (char *)p->data + ptr + 1; - } else - name = (char *)pkt_put(p, nl + 1); - - type = htons(*(uint16_t *)pkt_put(p, sizeof(type))); - clss = htons(*(uint16_t *)pkt_put(p, sizeof(clss))); - ttl = htonl(*(uint32_t *)pkt_put(p, sizeof(ttl))); - addr_size = htons(*(uint16_t *)pkt_put(p, sizeof(addr_size))); - - if (addr_size == sizeof(struct in_addr)) { - af = AF_INET; - } else if (addr_size == sizeof(struct in6_addr)) { - af = AF_INET6; - } else { - log_warn("Unexpected address size received: %d\n", addr_size); - break; - } - - if (!inet_ntop(af, pkt_put(p, addr_size), addr, ARRAY_SIZE(addr))) - strncpy(addr, "", sizeof(addr)); - - log_info("LLMNR response: %s IN %s %s (TTL %d)\n", name, query_type(type), addr, ttl); - } - } else - log_info("No LLMNR response received within timeout (%lu ms)\n", timeout_ms); - - if (i < count - 1) { - pkt_reset(p); - usleep(interval_ms * 1000); - } - } - - pkt_free(p); -err: - close(sock); - return 0; -} diff --git a/alpine/packages/llmnrd/src/llmnr.c b/alpine/packages/llmnrd/src/llmnr.c deleted file mode 100644 index a14468f89..000000000 --- a/alpine/packages/llmnrd/src/llmnr.c +++ /dev/null @@ -1,335 +0,0 @@ -/* - * Copyright (C) 2014-2015 Tobias Klauser - * - * This file is part of llmnrd. - * - * llmnrd is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * - * llmnrd is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with llmnrd. If not, see . - */ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "iface.h" -#include "log.h" -#include "pkt.h" -#include "socket.h" - -#include "iface.h" -#include "llmnr-packet.h" -#include "llmnr.h" - -static int llmnr_sock_ipv4 = -1; -static int llmnr_sock_ipv6 = -1; -static bool llmnr_running = true; -/* - * Host name in DNS name format (length octet + name + 0 byte) - */ -static char llmnr_hostname[LLMNR_LABEL_MAX_SIZE + 2]; - -static void llmnr_iface_event_handle(enum iface_event_type type, unsigned char af, - unsigned int ifindex) -{ - switch (af) { - case AF_INET: - socket_mcast_group_ipv4(llmnr_sock_ipv4, ifindex, type == IFACE_ADD); - break; - case AF_INET6: - socket_mcast_group_ipv6(llmnr_sock_ipv6, ifindex, type == IFACE_ADD); - break; - default: - /* ignore */ - break; - } -} - -int llmnr_init(const char *hostname, uint16_t port, bool ipv6) -{ - llmnr_hostname[0] = strlen(hostname); - strncpy(&llmnr_hostname[1], hostname, LLMNR_LABEL_MAX_SIZE); - llmnr_hostname[LLMNR_LABEL_MAX_SIZE + 1] = '\0'; - log_info("Starting llmnrd on port %u, hostname %s\n", port, hostname); - - llmnr_sock_ipv4 = socket_open_ipv4(port); - if (llmnr_sock_ipv4 < 0) - return -1; - - if (ipv6) { - llmnr_sock_ipv6 = socket_open_ipv6(port); - if (llmnr_sock_ipv6 < 0) - return -1; - } - - iface_register_event_handler(&llmnr_iface_event_handle); - - return 0; -} - -static bool llmnr_name_matches(const uint8_t *query) -{ - uint8_t i, n = llmnr_hostname[0]; - - /* length */ - if (query[0] != n) - return false; - /* NULL byte */ - if (query[1 + n] != 0) - return false; - - for (i = 1; i < llmnr_hostname[0]; i++) - if (tolower(query[i]) != tolower(llmnr_hostname[i])) - return false; - return true; -} - -static void llmnr_respond(unsigned int ifindex, const struct llmnr_hdr *hdr, - const uint8_t *query, size_t query_len, int sock, - const struct sockaddr_storage *sst) -{ - uint16_t qtype, qclass; - uint8_t name_len = query[0]; - /* skip name length & additional '\0' byte */ - const uint8_t *query_name_end = query + name_len + 2; - size_t i, n, response_len; - unsigned char family = AF_UNSPEC; - /* - * arbitrary restriction to 16 addresses per interface for the - * sake of a simple, atomic interface - */ - struct sockaddr_storage addrs[16]; - struct pkt *p; - struct llmnr_hdr *r; - - /* 4 bytes expected for QTYPE and QCLASS */ - if ((query_len - name_len - 2) < (sizeof(qtype) + sizeof(qclass))) - return; - - qtype = ntohs(*((uint16_t *)query_name_end)); - qclass = ntohs(*((uint16_t *)query_name_end + 1)); - - /* Ony IN queries supported */ - if (qclass != LLMNR_QCLASS_IN) - return; - - switch (qtype) { - case LLMNR_QTYPE_A: - family = AF_INET; - break; - case LLMNR_QTYPE_AAAA: - family = AF_INET6; - break; - case LLMNR_QTYPE_ANY: - family = AF_UNSPEC; - break; - default: - return; - } - - n = iface_addr_lookup(ifindex, family, addrs, ARRAY_SIZE(addrs)); - - /* - * This is the max response length (i.e. using all IPv6 addresses and - * not message compression). We might not use all of it. - */ - response_len = n * (1 + name_len + 1 + 2 + 2 + 4 + 2 + sizeof(struct in6_addr)); - p = pkt_alloc(sizeof(*hdr) + query_len + response_len); - - /* fill the LLMNR header */ - r = (struct llmnr_hdr *)pkt_put(p, sizeof(*r)); - r->id = hdr->id; - /* response flag */ - r->flags = htons(LLMNR_F_QR); - r->qdcount = hdr->qdcount; - r->ancount = htons(n); - r->nscount = 0; - r->arcount = 0; - - /* copy the original question */ - memcpy(pkt_put(p, query_len), query, query_len); - - /* append an RR for each address */ - for (i = 0; i < n; i++) { - void *addr; - size_t addr_size; - uint16_t type; - - if (addrs[i].ss_family == AF_INET) { - struct sockaddr_in *sin = (struct sockaddr_in *)&addrs[i]; - addr = &sin->sin_addr; - addr_size = sizeof(sin->sin_addr); - type = LLMNR_TYPE_A; - } else if (addrs[i].ss_family == AF_INET6) { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addrs[i]; - addr = &sin6->sin6_addr; - addr_size = sizeof(sin6->sin6_addr); - type = LLMNR_TYPE_AAAA; - } else - continue; - - /* NAME */ - if (i == 0) - memcpy(pkt_put(p, llmnr_hostname[0] + 2), llmnr_hostname, llmnr_hostname[0] + 2); - else { - /* message compression (RFC 1035, section 4.1.3) */ - uint16_t ptr = 0xC000 | (sizeof(*hdr) + query_len); - pkt_put_u16(p, ntohs(ptr)); - } - /* TYPE */ - pkt_put_u16(p, htons(type)); - /* CLASS */ - pkt_put_u16(p, htons(LLMNR_CLASS_IN)); - /* TTL */ - pkt_put_u32(p, htonl(LLMNR_TTL_DEFAULT)); - /* RDLENGTH */ - pkt_put_u16(p, htons(addr_size)); - /* RDATA */ - memcpy(pkt_put(p, addr_size), addr, addr_size); - } - - if (sendto(sock, p->data, pkt_len(p), 0, (struct sockaddr *)sst, sizeof(*sst)) < 0) - log_err("Failed to send response: %s\n", strerror(errno)); - - pkt_free(p); -} - -static void llmnr_packet_process(unsigned int ifindex, const uint8_t *pktbuf, size_t len, - int sock, const struct sockaddr_storage *sst) -{ - const struct llmnr_hdr *hdr = (const struct llmnr_hdr *)pktbuf; - uint16_t flags, qdcount; - const uint8_t *query; - size_t query_len; - uint8_t name_len; - - /* Query too short? */ - if (len < sizeof(struct llmnr_hdr)) - return; - - flags = ntohs(hdr->flags); - qdcount = ntohs(hdr->qdcount); - - /* Query invalid as per RFC 4795, section 2.1.1? */ - if (((flags & (LLMNR_F_QR | LLMNR_F_OPCODE)) != 0) || - qdcount != 1 || hdr->ancount != 0 || hdr->nscount != 0) - return; - - query = pktbuf + sizeof(struct llmnr_hdr); - query_len = len - sizeof(struct llmnr_hdr); - name_len = query[0]; - /* Invalid name in query? */ - if (name_len == 0 || name_len >= query_len || query[1 + name_len] != 0) - return; - - /* Authoritative? */ - if (llmnr_name_matches(query)) - llmnr_respond(ifindex, hdr, query, query_len, sock, sst); -} - -static void llmnr_recv(int sock) -{ - uint8_t pktbuf[2048], aux[128]; - struct msghdr msg; - struct iovec io; - struct sockaddr_storage sin_r; - struct cmsghdr *cmsg; - ssize_t recvlen; - int ifindex = -1; - - io.iov_base = pktbuf; - io.iov_len = sizeof(pktbuf); - - memset(&msg, 0, sizeof(msg)); - msg.msg_name = &sin_r; - msg.msg_namelen = sizeof(sin_r); - msg.msg_iov = &io; - msg.msg_iovlen = 1; - msg.msg_control = aux; - msg.msg_controllen = sizeof(aux); - - if ((recvlen = recvmsg(sock, &msg, 0)) < 0) { - if (errno != EINTR) - log_err("Failed to receive packet: %s\n", strerror(errno)); - return; - } - - for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { - if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) { - struct in_pktinfo *in = (struct in_pktinfo *)CMSG_DATA(cmsg); - ifindex = in->ipi_ifindex; - } else if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) { - struct in6_pktinfo *in6 = (struct in6_pktinfo *)CMSG_DATA(cmsg); - ifindex = in6->ipi6_ifindex; - } - } - - if (ifindex >= 0) - llmnr_packet_process(ifindex, pktbuf, recvlen, sock, - (const struct sockaddr_storage *)&sin_r); - else - log_warn("Could not get interface of incoming packet\n"); -} - -int llmnr_run(void) -{ - int ret = -1; - - while (llmnr_running) { - fd_set rfds; - struct timeval tv; - int nfds, ret; - - FD_ZERO(&rfds); - FD_SET(llmnr_sock_ipv4, &rfds); - if (llmnr_sock_ipv6 >= 0) { - FD_SET(llmnr_sock_ipv6, &rfds); - nfds = max(llmnr_sock_ipv4, llmnr_sock_ipv6) + 1; - } else - nfds = llmnr_sock_ipv4 + 1; - - tv.tv_sec = 0; - tv.tv_usec = 200; - - ret = select(nfds, &rfds, NULL, NULL, &tv); - if (ret < 0) { - if (errno != EINTR) - log_err("Failed to select() on socket: %s\n", strerror(errno)); - goto out; - } else if (ret) { - if (FD_ISSET(llmnr_sock_ipv4, &rfds)) - llmnr_recv(llmnr_sock_ipv4); - if (llmnr_sock_ipv6 >= 0 && FD_ISSET(llmnr_sock_ipv6, &rfds)) - llmnr_recv(llmnr_sock_ipv6); - } - } - - ret = 0; -out: - close(llmnr_sock_ipv4); - if (llmnr_sock_ipv6 >= 0) - close(llmnr_sock_ipv6); - return ret; -} - -void llmnr_stop(void) -{ - llmnr_running = false; -} diff --git a/alpine/packages/llmnrd/src/llmnr.h b/alpine/packages/llmnrd/src/llmnr.h deleted file mode 100644 index da864400c..000000000 --- a/alpine/packages/llmnrd/src/llmnr.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2015 Tobias Klauser - * - * This file is part of llmnrd. - * - * llmnrd is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * - * llmnrd is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with llmnrd. If not, see . - */ - -#ifndef LLMNR_H -#define LLMNR_H - -#include -#include - -int llmnr_init(const char *hostname, uint16_t port, bool ipv6); -int llmnr_run(void); -void llmnr_stop(void); - -#endif /* LLMNR_H */ diff --git a/alpine/packages/llmnrd/src/llmnrd.c b/alpine/packages/llmnrd/src/llmnrd.c deleted file mode 100644 index fb56b3002..000000000 --- a/alpine/packages/llmnrd/src/llmnrd.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * llmnrd -- LLMNR (RFC 4705) responder daemon. - * - * Copyright (C) 2014-2015 Tobias Klauser - * - * This file is part of llmnrd. - * - * llmnrd is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * - * llmnrd is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with llmnrd. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "compiler.h" -#include "log.h" -#include "util.h" - -#include "iface.h" -#include "llmnr.h" -#include "llmnr-packet.h" - -static const char *short_opts = "H:p:6dhV"; -static const struct option long_opts[] = { - { "hostname", required_argument, NULL, 'H' }, - { "port", required_argument, NULL, 'p' }, - { "ipv6", no_argument, NULL, '6' }, - { "daemonize", no_argument, NULL, 'd' }, - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'V' }, - { NULL, 0, NULL, 0 }, -}; - -static void __noreturn usage_and_exit(int status) -{ - fprintf(stdout, "Usage: llmnrd [OPTIONS]\n" - "Options:\n" - " -H, --hostname NAME set hostname to respond with (default: system hostname)\n" - " -p, --port NUM set port number to listen on (default: %d)\n" - " -6, --ipv6 enable LLMNR name resolution over IPv6\n" - " -d, --daemonize run as daemon in the background\n" - " -h, --help show this help and exit\n" - " -V, --version show version information and exit\n", - LLMNR_UDP_PORT); - exit(status); -} - -static void __noreturn version_and_exit(void) -{ - fprintf(stdout, "llmnrd %s %s\n" - "Copyright (C) 2014-2015 Tobias Klauser \n" - "Licensed under the GNU General Public License, version 2\n", - VERSION_STRING, GIT_VERSION); - exit(EXIT_SUCCESS); -} - -static void signal_handler(int sig) -{ - switch (sig) { - case SIGINT: - case SIGQUIT: - case SIGTERM: - log_info("Interrupt received. Stopping llmnrd.\n"); - iface_stop(); - llmnr_stop(); - break; - case SIGHUP: - default: - /* ignore */ - break; - } -} - -static void register_signal(int sig, void (*handler)(int)) -{ - sigset_t block_mask; - struct sigaction saction; - - sigfillset(&block_mask); - - saction.sa_handler = handler; - saction.sa_mask = block_mask; - - if (sigaction(sig, &saction, NULL) != 0) { - log_err("Failed to register signal handler for %s (%d)\n", - strsignal(sig), sig); - } -} - -int main(int argc, char **argv) -{ - int c, ret = EXIT_FAILURE; - long num_arg; - bool daemonize = false, ipv6 = false; - char *hostname = NULL; - uint16_t port = LLMNR_UDP_PORT; - - while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) { - switch (c) { - case 'd': - daemonize = true; - break; - case 'H': - hostname = xstrdup(optarg); - break; - case 'p': - num_arg = strtol(optarg, NULL, 0); - if (num_arg < 0 || num_arg > UINT16_MAX) { - log_err("Invalid port number: %ld\n", num_arg); - return EXIT_FAILURE; - } - port = num_arg; - case '6': - ipv6 = true; - break; - case 'V': - version_and_exit(); - case 'h': - usage_and_exit(EXIT_SUCCESS); - default: - usage_and_exit(EXIT_FAILURE); - } - } - - register_signal(SIGINT, signal_handler); - register_signal(SIGQUIT, signal_handler); - register_signal(SIGTERM, signal_handler); - register_signal(SIGHUP, signal_handler); - - if (!hostname) { - /* TODO: Consider hostname changing at runtime */ - hostname = xmalloc(255); - if (gethostname(hostname, 255) != 0) { - log_err("Failed to get hostname"); - return EXIT_FAILURE; - } - } - - if (daemonize) { - if (daemon(0, 0) != 0) { - log_err("Failed to daemonize process: %s\n", strerror(errno)); - return EXIT_FAILURE; - } - } - - if (llmnr_init(hostname, port, ipv6) < 0) - goto out; - - if (iface_start_thread() < 0) - goto out; - - ret = llmnr_run(); -out: - free(hostname); - return ret; -} diff --git a/alpine/packages/llmnrd/src/log.h b/alpine/packages/llmnrd/src/log.h deleted file mode 100644 index 03b77dc8a..000000000 --- a/alpine/packages/llmnrd/src/log.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2015 Tobias Klauser - * - * This file is part of llmnrd. - * - * llmnrd is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * - * llmnrd is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with llmnrd. If not, see . - */ - -#ifndef LOG_H -#define LOG_H - -#include - -#define log_err(fmt, args...) fprintf(stderr, "Error: " fmt, ##args) -#define log_warn(fmt, args...) fprintf(stderr, "Warning: " fmt, ##args) -#define log_info(fmt, args...) fprintf(stdout, fmt, ##args) -#ifdef DEBUG -# define log_dbg(fmt, args...) fprintf(stdout, fmt, ##args) -#else -# define log_dbg(fmt, args...) -#endif - -#endif /* LOG_H */ diff --git a/alpine/packages/llmnrd/src/pkt.h b/alpine/packages/llmnrd/src/pkt.h deleted file mode 100644 index e829b8c32..000000000 --- a/alpine/packages/llmnrd/src/pkt.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Packet buffer structure and utilities. - * - * Copyright (C) 2015 Tobias Klauser - * - * Based on pkt_buff.h from the netsniff-ng toolkit which is: - * - * Copyright (C) 2012 Christoph Jaeger - * - * This file is part of llmnrd. - * - * llmnrd is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * - * llmnrd is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with llmnrd. If not, see . - */ - -#ifndef PKT_H -#define PKT_H - -#include -#include -#include - -#include "log.h" -#include "util.h" - -struct pkt { - uint8_t *data; - uint8_t *tail; - size_t size; -}; - -static inline bool pkt_invariant(struct pkt *p) -{ - return p && (p->data <= p->tail); -} - -static inline struct pkt *pkt_alloc(size_t size) -{ - struct pkt *p = xmalloc(sizeof(*p) + size); - uint8_t *data = (uint8_t *)p + sizeof(*p); - - p->data = p->tail = data; - p->size = size; - - return p; -} - -static inline void pkt_free(struct pkt *p) -{ - free(p); -} - -static inline void pkt_reset(struct pkt *p) -{ - assert(pkt_invariant(p)); - - p->tail = p->data; -} - -static inline size_t pkt_len(struct pkt *p) -{ - assert(pkt_invariant(p)); - - return p->tail - p->data; -} - -static inline uint8_t *pkt_put(struct pkt *p, size_t len) -{ - uint8_t *data; - - assert(pkt_invariant(p)); - - if (pkt_len(p) + len <= p->size) { - data = p->tail; - p->tail += len; - } else { - /* grow packet */ - size_t new_size = p->size + len - pkt_len(p); - struct pkt *np = xrealloc(p, sizeof(*np) + new_size); - - log_dbg("Reallocating packet from %zu to %zu bytes\n", p->size, new_size); - data = (uint8_t *)np + sizeof(*np); - - np->data = data; - np->tail = data + pkt_len(p); - } - - return data; -} - -#define DEFINE_PKT_PUT(__bitwidth) \ -static inline void pkt_put_u##__bitwidth(struct pkt *p, uint##__bitwidth##_t val) \ -{ \ - uint##__bitwidth##_t *data = (uint##__bitwidth##_t *)pkt_put(p, sizeof(val)); \ - *data = val; \ -} - -DEFINE_PKT_PUT(8) -DEFINE_PKT_PUT(16) -DEFINE_PKT_PUT(32) - -#endif /* PKT_H */ diff --git a/alpine/packages/llmnrd/src/socket.c b/alpine/packages/llmnrd/src/socket.c deleted file mode 100644 index 0b0be78f4..000000000 --- a/alpine/packages/llmnrd/src/socket.c +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (C) 2014-2015 Tobias Klauser - * - * This file is part of llmnrd. - * - * llmnrd is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * - * llmnrd is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with llmnrd. If not, see . - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "llmnr-packet.h" -#include "log.h" -#include "socket.h" - -static const int YES = 1; - -int socket_open_ipv4(uint16_t port) -{ - int sock; - struct sockaddr_in sa; - - sock = socket(AF_INET, SOCK_DGRAM, 0); - if (sock < 0) { - log_err("Failed to open UDP socket: %s\n", strerror(errno)); - return -1; - } - - /* pass pktinfo struct on received packets */ - if (setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &YES, sizeof(YES)) < 0) { - log_err("Failed to set IPv4 packet info socket option: %s\n", strerror(errno)); - goto err; - } - - /* bind the socket */ - memset(&sa, 0, sizeof(sa)); - sa.sin_family = AF_INET; - sa.sin_addr.s_addr = INADDR_ANY; - sa.sin_port = htons(port); - - if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) { - log_err("Failed to bind() socket: %s\n", strerror(errno)); - goto err; - } - - return sock; -err: - close(sock); - return -1; -} - -int socket_open_ipv6(uint16_t port) -{ - int sock, opt_pktinfo; - struct sockaddr_in6 sa; - - sock = socket(AF_INET6, SOCK_DGRAM, 0); - if (sock < 0) { - log_err("Failed to open UDP socket: %s\n", strerror(errno)); - return -1; - } - - /* pass pktinfo struct on received packets */ -#if defined(IPV6_RECVPKTINFO) - opt_pktinfo = IPV6_RECVPKTINFO; -#elif defined(IPV6_PKTINFO) - opt_pktinfo = IPV6_PKTINFO; -#endif - if (setsockopt(sock, IPPROTO_IPV6, opt_pktinfo, &YES, sizeof(YES)) < 0) { - log_err("Failed to set IPv6 packet info socket option: %s\n", strerror(errno)); - goto err; - } - - /* IPv6 only socket */ - if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &YES, sizeof(YES)) < 0) { - log_err("Failed to set IPv6 only socket option: %s\n", strerror(errno)); - goto err; - } - - /* bind the socket */ - memset(&sa, 0, sizeof(sa)); - sa.sin6_family = AF_INET6; - sa.sin6_port = htons(port); - - if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) { - log_err("Failed to bind() socket: %s\n", strerror(errno)); - goto err; - } - - return sock; -err: - close(sock); - return -1; -} - -int socket_open_rtnl(void) -{ - int sock; - struct sockaddr_nl sa; - - sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (sock < 0) { - log_err("Failed to open netlink route socket: %s\n", strerror(errno)); - return -1; - } - - memset(&sa, 0, sizeof(sa)); - sa.nl_family = AF_NETLINK; - /* - * listen for following events: - * - network interface create/delete/up/down - * - IPv4 address add/delete - * - IPv6 address add/delete - */ - sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR; - - if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) { - log_err("Failed to bind() netlink socket: %s\n", strerror(errno)); - goto err; - } - - return sock; -err: - close(sock); - return -1; -} - -int socket_mcast_group_ipv4(int sock, unsigned int ifindex, bool join) -{ - struct ip_mreqn mreq; - char ifname[IF_NAMESIZE]; - - /* silently ignore, we might not be listening on an IPv4 socket */ - if (sock < 0) - return -1; - - memset(&mreq, 0, sizeof(mreq)); - mreq.imr_ifindex = ifindex; - mreq.imr_address.s_addr = INADDR_ANY; - inet_pton(AF_INET, LLMNR_IPV4_MCAST_ADDR, &mreq.imr_multiaddr); - - if (setsockopt(sock, IPPROTO_IP, join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, - &mreq, sizeof(mreq)) < 0) { - log_err("Failed to join IPv4 multicast group on interface %s: %s\n", - if_indextoname(ifindex, ifname), strerror(errno)); - return -1; - } - - return 0; -} - -int socket_mcast_group_ipv6(int sock, unsigned int ifindex, bool join) -{ - struct ipv6_mreq mreq6; - char ifname[IF_NAMESIZE]; - - /* silently ignore, we might not be listening on an IPv6 socket */ - if (sock < 0) - return -1; - - memset(&mreq6, 0, sizeof(mreq6)); - mreq6.ipv6mr_interface = ifindex; - inet_pton(AF_INET6, LLMNR_IPV6_MCAST_ADDR, &mreq6.ipv6mr_multiaddr); - - if (setsockopt(sock, IPPROTO_IPV6, join ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP, - &mreq6, sizeof(mreq6)) < 0) { - log_err("Failed to join IPv6 multicast group on interface %s: %s\n", - if_indextoname(ifindex, ifname), strerror(errno)); - return -1; - } - - return 0; -} diff --git a/alpine/packages/llmnrd/src/socket.h b/alpine/packages/llmnrd/src/socket.h deleted file mode 100644 index bb555c824..000000000 --- a/alpine/packages/llmnrd/src/socket.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2014-2015 Tobias Klauser - * - * This file is part of llmnrd. - * - * llmnrd is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * - * llmnrd is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with llmnrd. If not, see . - */ - -#ifndef SOCKET_H -#define SOCKET_H - -#include -#include - -int socket_open_ipv4(uint16_t port); -int socket_open_ipv6(uint16_t port); -int socket_open_rtnl(void); - -int socket_mcast_group_ipv4(int sock, unsigned int ifindex, bool join); -int socket_mcast_group_ipv6(int sock, unsigned int ifindex, bool join); - -#endif /* SOCKET_H */ diff --git a/alpine/packages/llmnrd/src/util.c b/alpine/packages/llmnrd/src/util.c deleted file mode 100644 index e399f3194..000000000 --- a/alpine/packages/llmnrd/src/util.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2014-2015 Tobias Klauser - * Copyright (C) 2009-2012 Daniel Borkmann - * - * This file is part of llmnrd. - * - * llmnrd is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * - * llmnrd is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with llmnrd. If not, see . - */ - -#include -#include - -#include "util.h" - -void *xmalloc(size_t size) -{ - void *ptr; - - if (size == 0) - panic("malloc: size 0\n"); - - ptr = malloc(size); - if (!ptr) - panic("malloc: out of memory\n"); - - return ptr; -} - -void *xzalloc(size_t size) -{ - void *ptr = xmalloc(size); - memset(ptr, 0, size); - return ptr; -} - -void *xrealloc(void *ptr, size_t size) -{ - void *newptr; - - if (size == 0) - panic("realloc: size 0\n"); - - newptr = realloc(ptr, size); - if (!newptr) { - free(ptr); - panic("realloc: out of memory\n"); - } - - return newptr; -} - -char *xstrdup(const char *s) -{ - size_t len = strlen(s) + 1; - char *ret = xmalloc(len); - - memcpy(ret, s, len); - - return ret; -} diff --git a/alpine/packages/llmnrd/src/util.h b/alpine/packages/llmnrd/src/util.h deleted file mode 100644 index 0c3d26344..000000000 --- a/alpine/packages/llmnrd/src/util.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2014-2015 Tobias Klauser - * Copyright (C) 2009-2012 Daniel Borkmann - * - * This file is part of llmnrd. - * - * llmnrd is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * - * llmnrd is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with llmnrd. If not, see . - */ - -#ifndef UTIL_H -#define UTIL_H - -#include -#include -#include -#include - -#include "compiler.h" - -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) - -/* - * min()/max() macros with strict type-checking. - * Taken from linux/kernel.h - */ -#undef min -#define min(x, y) ({ \ - typeof(x) _min1 = (x); \ - typeof(y) _min2 = (y); \ - (void) (&_min1 == &_min2); \ - _min1 < _min2 ? _min1 : _min2; }) - -#undef max -#define max(x, y) ({ \ - typeof(x) _max1 = (x); \ - typeof(y) _max2 = (y); \ - (void) (&_max1 == &_max2); \ - _max1 > _max2 ? _max1 : _max2; }) - -static inline void __noreturn panic(const char *fmt, ...) -{ - va_list vl; - - va_start(vl, fmt); - vfprintf(stderr, fmt, vl); - va_end(vl); - - exit(EXIT_FAILURE); -} - -void *xmalloc(size_t size) __warn_unused_result; -void *xzalloc(size_t size) __warn_unused_result; -void *xrealloc(void *ptr, size_t size) __warn_unused_result; -char *xstrdup(const char *s) __warn_unused_result; - -static inline bool xstreq(const char *str1, const char *str2) -{ - size_t n = strlen(str1); - - if (n != strlen(str2)) - return false; - if (strncmp(str1, str2, n) != 0) - return false; - - return true; -} - -#endif /* UTIL_H */