diff --git a/libs/libcap/Makefile b/libs/libcap/Makefile new file mode 100644 index 0000000000..418033dd42 --- /dev/null +++ b/libs/libcap/Makefile @@ -0,0 +1,56 @@ +# +# Copyright (C) 2011 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=libcap +PKG_VERSION:=2.24 +PKG_RELEASE:=1 + +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz +PKG_SOURCE_URL:=http://www.kernel.org/pub/linux/libs/security/linux-privs/libcap2/ +PKG_MD5SUM:=d43ab9f680435a7fff35b4ace8d45b80 +PKG_MAINTAINER:=Steven Barth + +PKG_INSTALL:=1 + +include $(INCLUDE_DIR)/package.mk +include $(INCLUDE_DIR)/kernel.mk + +define Package/libcap + TITLE:=Linux capabilities library + SECTION:=libs + CATEGORY:=Libraries + URL:=http://www.kernel.org/pub/linux/libs/security/linux-privs/libcap2/ +endef + +MAKE_FLAGS += \ + CFLAGS="$(TARGET_CFLAGS)" \ + BUILD_CC="$(CC)" \ + BUILD_CFLAGS="$(FPIC) -I$(PKG_BUILD_DIR)/libcap/include" \ + CFLAGS="$(TARGET_CFLAGS)" \ + LD="$(TARGET_CC)" \ + LDFLAGS="$(TARGET_LDFLAGS) -shared" \ + INDENT="| true" \ + PAM_CAP="no" \ + LIBATTR="no" \ + DYNAMIC="yes" \ + lib="lib" + +define Build/InstallDev + $(INSTALL_DIR) $(1)/usr/include/sys + $(CP) $(PKG_INSTALL_DIR)/usr/include/* $(1)/usr/include/ + $(INSTALL_DIR) $(1)/usr/lib/ + $(CP) $(PKG_INSTALL_DIR)/lib/* $(1)/usr/lib/ +endef + +define Package/libcap/install + $(INSTALL_DIR) $(1)/usr/lib + $(CP) $(PKG_INSTALL_DIR)/lib/libcap.so* $(1)/usr/lib/ +endef + +$(eval $(call BuildPackage,libcap)) diff --git a/net/mdnsresponder/Makefile b/net/mdnsresponder/Makefile new file mode 100644 index 0000000000..7e36ceb5e3 --- /dev/null +++ b/net/mdnsresponder/Makefile @@ -0,0 +1,166 @@ +# +# Copyright (C) 2009-2014 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=mDNSResponder +PKG_VERSION:=544 +PKG_RELEASE:=4 + +PKG_SOURCE:=mDNSResponder-$(PKG_VERSION).tar.gz +PKG_SOURCE_URL:=http://opensource.apple.com/tarballs/mDNSResponder/ +PKG_MD5SUM:=39142ab70bd82a096801ce346f86cbab +PKG_MAINTAINER:=Steven Barth + +PKG_BUILD_DIR:=$(BUILD_DIR)/mDNSResponder-$(PKG_VERSION) + +PKG_BUILD_PARALLEL:=0 +PKG_INSTALL:=1 + +include $(INCLUDE_DIR)/package.mk + +# sys/capability.h is not part of *libc* +PKG_BUILD_DEPENDS:=libcap + +define Package/mDNSResponder/Default + SECTION:=net + CATEGORY:=Network + SUBMENU:=IP Addresses and Names + TITLE:=mDNS + URL:=http://developer.apple.com/networking/bonjour/ +endef + +define Package/mDNSResponder/Default/description + Bonjour, also known as zero-configuration networking, enables + automatic discovery of computers, devices, and services on + IP networks. +endef + +define Package/mdns-utils +$(call Package/mDNSResponder/Default) + TITLE+= client utilities + DEPENDS+= +mdnsd +endef + +define Package/mdns-utils/description +$(call Package/mDNSResponder/Default/description) + . + This package contains mDNS client utilities: + - dns-sd + - mDNSClient + - mDNSIdentify + - mDNSNetMonitor + - mDNSProxyResponder + - mDNSResponder +endef + +define Package/mdnsd +$(call Package/mDNSResponder/Default) + TITLE+= server daemon +endef + +define Package/mdnsd/description +$(call Package/mDNSResponder/Default/description) + . + This package contains the mDNS server daemon. +endef + +define Package/mdnsresponder +$(call Package/mDNSResponder/Default) + TITLE+= suite (meta) + DEPENDS+= +mdns-utils +mdnsd +endef + +define Package/mdnsresponder/description +$(call Package/mDNSResponder/Default/description) + . + This meta package contains only dependencies on other packages. +endef + +# I have no idea why -lc is required, but without it, C library symbols are +# not found: +MAKE_FLAGS += \ + CFLAGS_DEBUG="$(TARGET_CFLAGS)" \ + LINKOPTS=-lc \ + LDCONFIG= \ + ETCBASE="$(PKG_INSTALL_DIR)/etc" \ + INSTBASE="$(PKG_INSTALL_DIR)/usr" \ + NSSINSTPATH="$(PKG_INSTALL_DIR)/lib" \ + MANPATH="$(PKG_INSTALL_DIR)/usr/man" \ + STARTUPSCRIPTDIR="$(PKG_INSTALL_DIR)/etc/init.d" \ + RUNLEVELSCRIPTSDIR="$(PKG_INSTALL_DIR)/etc/rc.d" \ + os=linux-uclibc +MAKE_PATH = mDNSPosix + +define Build/Compile + $(call Build/Compile/Default) + # XXX: mDNSResponder's "make install" does not seem to create: + mkdir -p $(PKG_INSTALL_DIR)/lib/ + mkdir -p $(PKG_INSTALL_DIR)/usr/bin/ + mkdir -p $(PKG_INSTALL_DIR)/usr/sbin/ + mkdir -p $(PKG_INSTALL_DIR)/usr/lib/ + mkdir -p $(PKG_INSTALL_DIR)/usr/man/man5/ + mkdir -p $(PKG_INSTALL_DIR)/usr/man/man8/ + mkdir -p $(PKG_INSTALL_DIR)/usr/include/ + mkdir -p $(PKG_INSTALL_DIR)/etc/ + mkdir -p $(PKG_INSTALL_DIR)/etc/init.d/ + mkdir -p $(PKG_INSTALL_DIR)/etc/rc.d/ + mkdir -p $(PKG_INSTALL_DIR)/etc/rc.d/rc2.d/ + mkdir -p $(PKG_INSTALL_DIR)/etc/rc.d/rc3.d/ + mkdir -p $(PKG_INSTALL_DIR)/etc/rc.d/rc4.d/ + mkdir -p $(PKG_INSTALL_DIR)/etc/rc.d/rc5.d/ + mkdir -p $(PKG_INSTALL_DIR)/etc/rc.d/rc0.d/ + mkdir -p $(PKG_INSTALL_DIR)/etc/rc.d/rc6.d/ +endef + +define Build/InstallDev + $(INSTALL_DIR) $(1)/usr/include + $(CP) $(PKG_BUILD_DIR)/mDNSShared/dns_sd.h $(1)/usr/include/ + $(INSTALL_DIR) $(1)/usr/lib + $(CP) $(PKG_BUILD_DIR)/mDNSPosix/build/prod/*.so* $(1)/usr/lib/ +endef + +define Package/mdns-utils/conffile + /etc/init.d/mDNSResponder +endef + +define Package/mdns-utils/install + $(INSTALL_DIR) $(1)/usr/bin/ + $(CP) $(PKG_INSTALL_DIR)/usr/bin/dns-sd $(1)/usr/bin/ + $(CP) $(PKG_BUILD_DIR)/mDNSPosix/build/prod/mDNSClientPosix $(1)/usr/bin/mDNSClient + $(CP) $(PKG_BUILD_DIR)/mDNSPosix/build/prod/mDNSIdentify $(1)/usr/bin/mDNSIdentify + $(CP) $(PKG_BUILD_DIR)/mDNSPosix/build/prod/mDNSNetMonitor $(1)/usr/bin/mDNSNetMonitor + $(CP) $(PKG_BUILD_DIR)/mDNSPosix/build/prod/mDNSProxyResponderPosix $(1)/usr/bin/mDNSProxyResponder + $(CP) $(PKG_BUILD_DIR)/mDNSPosix/build/prod/mDNSResponderPosix $(1)/usr/bin/mDNSResponder + $(INSTALL_DIR) $(1)/etc + $(INSTALL_DATA) ./files/mDNSResponder.conf $(1)/etc/ + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) ./files/mDNSResponder.init $(1)/etc/init.d/mDNSResponder +endef + +define Package/mdns-utils/conffiles +/etc/mDNSResponder.conf +endef + +define Package/mdnsd/install + $(INSTALL_DIR) $(1)/usr/sbin/ + $(CP) $(PKG_INSTALL_DIR)/usr/sbin/mdnsd $(1)/usr/sbin/ + $(INSTALL_DIR) $(1)/etc/hotplug.d/iface + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) ./files/mdnsd.init $(1)/etc/init.d/mdnsd + $(INSTALL_DIR) $(1)/usr/lib/ + $(CP) $(PKG_INSTALL_DIR)/usr/lib/libdns_sd.so.1 $(1)/usr/lib/ + $(LN) -s libdns_sd.so.1 $(1)/usr/lib/libdns_sd.so +endef + +define Package/mdnsresponder/install + : +endef + +$(eval $(call BuildPackage,mdns-utils)) +$(eval $(call BuildPackage,mdnsd)) +$(eval $(call BuildPackage,mdnsresponder)) diff --git a/net/mdnsresponder/files/mDNSResponder.conf b/net/mdnsresponder/files/mDNSResponder.conf new file mode 100644 index 0000000000..23aab169aa --- /dev/null +++ b/net/mdnsresponder/files/mDNSResponder.conf @@ -0,0 +1,4 @@ +"OpenWrt SSH" +_ssh._tcp. local +22 +OpenWrt SSH server diff --git a/net/mdnsresponder/files/mDNSResponder.init b/net/mdnsresponder/files/mDNSResponder.init new file mode 100644 index 0000000000..87f9e90082 --- /dev/null +++ b/net/mdnsresponder/files/mDNSResponder.init @@ -0,0 +1,14 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2009-2011 OpenWrt.org + +START=61 + +SERVICE_USE_PID=1 + +start() { + service_start /usr/bin/mDNSResponder -b -f /etc/mDNSResponder.conf +} + +stop() { + service_stop /usr/bin/mDNSResponder +} diff --git a/net/mdnsresponder/files/mdnsd.init b/net/mdnsresponder/files/mdnsd.init new file mode 100755 index 0000000000..817604babb --- /dev/null +++ b/net/mdnsresponder/files/mdnsd.init @@ -0,0 +1,14 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2009-2014 OpenWrt.org + +START=60 +STOP=10 +USE_PROCD=1 + +start_service() { + procd_open_instance + procd_set_param command /usr/sbin/mdnsd -debug + procd_set_param respawn + procd_close_instance +} + diff --git a/net/mdnsresponder/patches/001-cross_compile.patch b/net/mdnsresponder/patches/001-cross_compile.patch new file mode 100644 index 0000000000..f824d5e26b --- /dev/null +++ b/net/mdnsresponder/patches/001-cross_compile.patch @@ -0,0 +1,123 @@ +--- a/Clients/Makefile ++++ b/Clients/Makefile +@@ -23,6 +23,8 @@ + + ############################################################################# + ++CC = @cc ++ + # On OS X the dns_sd library functions are included in libSystem, which is implicitly linked with every executable + # If /usr/lib/libSystem.dylib exists, then we're on OS X, so we don't need also to link the "dns_sd" shared library + ifneq "$(wildcard /usr/lib/libSystem.dylib)" "" +@@ -42,10 +44,10 @@ build: + mkdir build + + build/dns-sd: build dns-sd.c ClientCommon.c +- cc $(filter %.c %.o, $+) $(LIBS) -I../mDNSShared -Wall -o $@ ++ $(CC) $(CFLAGS) $(filter %.c %.o, $+) $(LIBS) -I../mDNSShared -Wall -o $@ + + build/dns-sd64: build dns-sd.c ClientCommon.c +- cc $(filter %.c %.o, $+) $(LIBS) -I../mDNSShared -Wall -o $@ -m64 ++ $(CC) $(CFLAGS) $(filter %.c %.o, $+) $(LIBS) -I../mDNSShared -Wall -o $@ -m64 + + # Note, we can make a 'fat' version of dns-sd using 'lipo', as shown below, but we + # don't, because we don't want or need a 'fat' version of dns-sd, because it will +--- a/mDNSPosix/Makefile ++++ b/mDNSPosix/Makefile +@@ -54,10 +54,11 @@ COREDIR = ../mDNSCore + SHAREDDIR ?= ../mDNSShared + JDK = /usr/jdk + +-CC = @cc ++CC = @gcc + BISON = @bison + FLEX = @flex +-LD = ld -shared ++LD = @ld ++SOOPTS = -shared + CP = cp + RM = rm + LN = ln -s -f +@@ -82,7 +83,7 @@ else + CFLAGS_DEBUG = -Os -DMDNS_DEBUGMSGS=0 + OBJDIR ?= objects/prod + BUILDDIR ?= build/prod +-STRIP = strip -S ++STRIP = @strip -S + endif + + # Configure per-OS peculiarities +@@ -91,7 +92,7 @@ CFLAGS_DEBUG = -O0 -DMDNS_DEBUGMSGS=0 + CFLAGS_OS = -DNOT_HAVE_DAEMON -DNOT_HAVE_SA_LEN -DNOT_HAVE_SOCKLEN_T -DNOT_HAVE_IF_NAMETOINDEX \ + -DLOG_PERROR=0 -D_XPG4_2 -D__EXTENSIONS__ -DHAVE_BROKEN_RECVIF_NAME -DTARGET_OS_SOLARIS + CC = gcc +-LD = gcc -shared ++LD = gcc + LINKOPTS = -lsocket -lnsl -lresolv + JAVACFLAGS_OS += -I$(JDK)/include/solaris + ifneq ($(DEBUG),1) +@@ -147,7 +148,8 @@ CFLAGS_OS = -DHAVE_IPV6 -no-cpp-precomp + -D__MAC_OS_X_VERSION_MIN_REQUIRED=__MAC_OS_X_VERSION_10_4 \ + -D__APPLE_USE_RFC_2292 #-Wunreachable-code + CC = gcc +-LD = $(CC) -dynamiclib ++LD = $(CC) ++SOOPTS= -dynamiclib + LINKOPTS = -lSystem + LDSUFFIX = dylib + JDK = /System/Library/Frameworks/JavaVM.framework/Home +@@ -169,8 +171,9 @@ NSSLIBFILE := $(NSSLIBNAME)-$(NSSVERSIO + NSSLINKNAME := $(NSSLIBNAME).so.2 + NSSINSTPATH := /lib + +-# If not otherwise defined, we install into /usr/lib and /usr/include ++# If not otherwise defined, we install into /usr/lib, /usr/include and /etc + # and our startup script is called mdns (e.g. /etc/init.d/mdns) ++ETCBASE?=/etc + INSTBASE?=/usr + STARTUPSCRIPTNAME?=mdns + +@@ -256,7 +259,7 @@ libdns_sd: setup $(BUILDDIR)/libdns_sd.$ + CLIENTLIBOBJS = $(OBJDIR)/dnssd_clientlib.c.so.o $(OBJDIR)/dnssd_clientstub.c.so.o $(OBJDIR)/dnssd_ipc.c.so.o + + $(BUILDDIR)/libdns_sd.$(LDSUFFIX): $(CLIENTLIBOBJS) +- @$(LD) $(LINKOPTS) -o $@ $+ ++ @$(LD) $(SOOPTS) $(LINKOPTS) -o $@ $+ + @$(STRIP) $@ + + Clients: setup libdns_sd ../Clients/build/dns-sd +@@ -291,7 +294,7 @@ InstalledManPages: $(MANPATH)/man8/mdnsd + InstalledClients: $(INSTBASE)/bin/dns-sd + @echo $+ " installed" + +-InstalledNSS: $(NSSINSTPATH)/$(NSSLINKNAME) /etc/nss_mdns.conf $(MANPATH)/man5/nss_mdns.conf.5 $(MANPATH)/man8/libnss_mdns.8 ++InstalledNSS: $(NSSINSTPATH)/$(NSSLINKNAME) $(ETCBASE)/nss_mdns.conf $(MANPATH)/man5/nss_mdns.conf.5 $(MANPATH)/man8/libnss_mdns.8 + @echo $+ " installed" + + # Note: If daemon already installed, we make sure it's stopped before overwriting it +@@ -346,19 +349,21 @@ $(INSTBASE)/bin/dns-sd: ../Clients/build + + $(NSSINSTPATH)/$(NSSLINKNAME): $(NSSINSTPATH)/$(NSSLIBFILE) + $(LN) $< $@ +- ldconfig ++ifdef LDCONFIG ++ $(LDCONFIG) ++endif + + $(NSSINSTPATH)/$(NSSLIBFILE): $(BUILDDIR)/$(NSSLIBFILE) + $(CP) $< $@ + chmod 444 $@ + +-/etc/nss_mdns.conf: nss_mdns.conf ++$(ETCBASE)/nss_mdns.conf: nss_mdns.conf + $(CP) $< $@ + chmod 444 $@ + # Check the nsswitch.conf file. + # If 'mdns' does not already appear on the "hosts:" line, then add it right before 'dns' +- cp -f /etc/nsswitch.conf /etc/nsswitch.conf.pre-mdns +- sed -e '/mdns/!s/^\(hosts:.*\)dns\(.*\)/\1mdns dns\2/' /etc/nsswitch.conf.pre-mdns > /etc/nsswitch.conf ++ -[ -f $(ETCBASE)/nsswitch.conf ] && cp -f $(ETCBASE)/nsswitch.conf $(ETCBASE)/nsswitch.conf.pre-mdns ++ -[ -f $(ETCBASE)/nsswitch.conf ] && sed -e '/mdns/!s/^\(hosts:.*\)dns\(.*\)/\1mdns dns\2/' $(ETCBASE)/nsswitch.conf.pre-mdns > $(ETCBASE)/nsswitch.conf + + ############################################################################# + diff --git a/net/mdnsresponder/patches/100-linux_fixes.patch b/net/mdnsresponder/patches/100-linux_fixes.patch new file mode 100644 index 0000000000..851dd31dfe --- /dev/null +++ b/net/mdnsresponder/patches/100-linux_fixes.patch @@ -0,0 +1,562 @@ +diff --git a/.gitignore b/.gitignore +new file mode 100644 +index 0000000..920cdfc +--- /dev/null ++++ b/.gitignore +@@ -0,0 +1,4 @@ ++Clients/build ++mDNSPosix/build ++mDNSPosix/objects ++ +diff --git a/mDNSPosix/PosixDaemon.c b/mDNSPosix/PosixDaemon.c +index 88b3292..e86a6c7 100644 +--- a/mDNSPosix/PosixDaemon.c ++++ b/mDNSPosix/PosixDaemon.c +@@ -37,6 +37,11 @@ + #include + #include + #include ++#ifdef __linux__ ++#include /* !!! We require libcap-dev for this. Oh well. */ ++/* prctl is required to enable inheriting of capabilities across setuid */ ++#include ++#endif /* __linux__ */ + + #if __APPLE__ + #undef daemon +@@ -184,16 +189,50 @@ int main(int argc, char **argv) + + Reconfigure(&mDNSStorage); + ++#ifdef __linux__ ++ /* ++ * SO_BINDTODEVICE is privileged operation; however, we can get ++ * around it using capabilities instead of remaining root. ++ */ ++ if (mStatus_NoError == err) ++ { ++ if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) ++ perror("prctl PR_SET_KEEPCAPS"); ++ } ++#endif /* __linux__ */ ++ + // Now that we're finished with anything privileged, switch over to running as "nobody" + if (mStatus_NoError == err) + { + const struct passwd *pw = getpwnam("nobody"); + if (pw != NULL) ++ { + setuid(pw->pw_uid); ++#ifdef __linux__ ++ struct __user_cap_header_struct ch; ++ struct __user_cap_data_struct cd[_LINUX_CAPABILITY_U32S_3]; ++ ++ memset(&ch, 0, sizeof(ch)); ++ ch.version = _LINUX_CAPABILITY_VERSION_3; ++ ch.pid = getpid(); ++ memset(&cd[0], 0, sizeof(cd)); ++ /* CAP_NET_RAW is required to use SO_BINDTODEVICE */ ++ int caps = CAP_TO_MASK(CAP_NET_RAW); ++ cd[0].permitted = caps; ++ cd[0].effective = caps; ++ if (capset(&ch, &cd[0]) < 0) ++ perror("capset"); ++#endif /* __linux__ */ ++ } + else + LogMsg("WARNING: mdnsd continuing as root because user \"nobody\" does not exist"); + } + ++#ifdef __linux__ ++ if (mStatus_NoError == err) ++ err = mDNSPlatformPosixRefreshInterfaceList(&mDNSStorage); ++#endif /* __linux__ */ ++ + if (mStatus_NoError == err) + err = MainLoop(&mDNSStorage); + +diff --git a/mDNSPosix/Responder.c b/mDNSPosix/Responder.c +index 3996b7b..e58d8eb 100755 +--- a/mDNSPosix/Responder.c ++++ b/mDNSPosix/Responder.c +@@ -603,7 +603,8 @@ static mStatus RegisterServicesInFile(const char *filePath) + status = mStatus_UnknownErr; + } + +- assert(0 == fclose(fp)); ++ int rv = fclose(fp); ++ assert(0 == rv); + + return status; + } +diff --git a/mDNSPosix/mDNSPosix.c b/mDNSPosix/mDNSPosix.c +index 953bf64..4e481ea 100755 +--- a/mDNSPosix/mDNSPosix.c ++++ b/mDNSPosix/mDNSPosix.c +@@ -136,7 +136,7 @@ mDNSlocal void SockAddrTomDNSAddr(const struct sockaddr *const sa, mDNSAddr *ipA + + // mDNS core calls this routine when it needs to send a packet. + mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end, +- mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst, ++ mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst, + mDNSIPPort dstPort, mDNSBool useBackgroundTrafficClass) + { + int err = 0; +@@ -574,9 +574,17 @@ mDNSlocal void FreePosixNetworkInterface(PosixNetworkInterface *intf) + { + assert(intf != NULL); + if (intf->intfName != NULL) free((void *)intf->intfName); +- if (intf->multicastSocket4 != -1) assert(close(intf->multicastSocket4) == 0); ++ if (intf->multicastSocket4 != -1) ++ { ++ int rv = close(intf->multicastSocket4); ++ assert(rv == 0); ++ } + #if HAVE_IPV6 +- if (intf->multicastSocket6 != -1) assert(close(intf->multicastSocket6) == 0); ++ if (intf->multicastSocket6 != -1) ++ { ++ int rv = close(intf->multicastSocket6); ++ assert(rv == 0); ++ } + #endif + free(intf); + } +@@ -703,6 +711,29 @@ mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interf + if (err < 0) { err = errno; perror("setsockopt - IP_MULTICAST_TTL"); } + } + ++#ifdef __linux__ ++#ifdef SO_BINDTODEVICE ++ if (err == 0 && interfaceIndex) ++ { ++ char ifname[IFNAMSIZ]; ++ if (if_indextoname(interfaceIndex, ifname)) ++ { ++ err = setsockopt(*sktPtr, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname)); ++ if (err < 0) ++ { ++ err = errno; ++ perror("setsockopt - SO_BINDTODEVICE"); ++ } ++ } ++ else ++ { ++ err = errno; ++ perror("if_indextoname"); ++ } ++ } ++#endif /* SO_BINDTODEVICE */ ++#endif /* __linux__ */ ++ + // And start listening for packets + if (err == 0) + { +@@ -784,6 +815,29 @@ mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interf + if (err < 0) { err = errno; perror("setsockopt - IPV6_MULTICAST_HOPS"); } + } + ++#ifdef __linux__ ++#ifdef SO_BINDTODEVICE ++ if (err == 0 && interfaceIndex) ++ { ++ char ifname[IFNAMSIZ]; ++ if (if_indextoname(interfaceIndex, ifname)) ++ { ++ err = setsockopt(*sktPtr, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname)); ++ if (err < 0) ++ { ++ err = errno; ++ perror("setsockopt - SO_BINDTODEVICE"); ++ } ++ } ++ else ++ { ++ err = errno; ++ perror("if_indextoname"); ++ } ++ } ++#endif /* SO_BINDTODEVICE */ ++#endif /* __linux__ */ ++ + // And start listening for packets + if (err == 0) + { +@@ -815,7 +869,12 @@ mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interf + } + + // Clean up +- if (err != 0 && *sktPtr != -1) { assert(close(*sktPtr) == 0); *sktPtr = -1; } ++ if (err != 0 && *sktPtr != -1) ++ { ++ int rv = close(*sktPtr); ++ assert(rv == 0); ++ *sktPtr = -1; ++ } + assert((err == 0) == (*sktPtr != -1)); + return err; + } +@@ -994,7 +1053,7 @@ mDNSlocal mStatus OpenIfNotifySocket(int *pFD) + /* Subscribe the socket to Link & IP addr notifications. */ + mDNSPlatformMemZero(&snl, sizeof snl); + snl.nl_family = AF_NETLINK; +- snl.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR; ++ snl.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR; + ret = bind(sock, (struct sockaddr *) &snl, sizeof snl); + if (0 == ret) + *pFD = sock; +@@ -1072,11 +1131,18 @@ mDNSlocal mDNSu32 ProcessRoutingNotification(int sd) + PrintNetLinkMsg(pNLMsg); + #endif + ++ // this result isn't used anywhere as a number, just as ++ // non-zero - however, I have seen devices with more than 32 ++ // interfaces at some point.. ++ // (on Linux, every tunnel increases index for example) ++ + // Process the NetLink message + if (pNLMsg->nlmsg_type == RTM_GETLINK || pNLMsg->nlmsg_type == RTM_NEWLINK) +- result |= 1 << ((struct ifinfomsg*) NLMSG_DATA(pNLMsg))->ifi_index; ++ result |= 1; ++ // << ((struct ifinfomsg*) NLMSG_DATA(pNLMsg))->ifi_index; + else if (pNLMsg->nlmsg_type == RTM_DELADDR || pNLMsg->nlmsg_type == RTM_NEWADDR) +- result |= 1 << ((struct ifaddrmsg*) NLMSG_DATA(pNLMsg))->ifa_index; ++ result |= 1; ++ // << ((struct ifaddrmsg*) NLMSG_DATA(pNLMsg))->ifa_index; + + // Advance pNLMsg to the next message in the buffer + if ((pNLMsg->nlmsg_flags & NLM_F_MULTI) != 0 && pNLMsg->nlmsg_type != NLMSG_DONE) +@@ -1247,8 +1313,12 @@ mDNSexport mStatus mDNSPlatformInit(mDNS *const m) + if (err == mStatus_NoError) err = SetupSocket(&sa, zeroIPPort, 0, &m->p->unicastSocket6); + #endif + ++ // In Linux case, we can't set up sockets with different owner - ++ // it blows up SO_REUSEPORT. So we do this step bit later. ++#ifndef __linux__ + // Tell mDNS core about the network interfaces on this machine. + if (err == mStatus_NoError) err = SetupInterfaceList(m); ++#endif /* !__linux__ */ + + // Tell mDNS core about DNS Servers + mDNS_Lock(m); +@@ -1281,9 +1351,17 @@ mDNSexport void mDNSPlatformClose(mDNS *const m) + { + assert(m != NULL); + ClearInterfaceList(m); +- if (m->p->unicastSocket4 != -1) assert(close(m->p->unicastSocket4) == 0); ++ if (m->p->unicastSocket4 != -1) ++ { ++ int rv = close(m->p->unicastSocket4); ++ assert(rv == 0); ++ } + #if HAVE_IPV6 +- if (m->p->unicastSocket6 != -1) assert(close(m->p->unicastSocket6) == 0); ++ if (m->p->unicastSocket6 != -1) ++ { ++ int rv = close(m->p->unicastSocket6); ++ assert(rv == 0); ++ } + #endif + } + +@@ -1533,14 +1611,14 @@ mDNSexport mStatus mDNSPlatformClearSPSMACAddr(void) + mDNSexport mDNSu16 mDNSPlatformGetUDPPort(UDPSocket *sock) + { + (void) sock; // unused +- ++ + return (mDNSu16)-1; + } + + mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID) + { + (void) InterfaceID; // unused +- ++ + return mDNSfalse; + } + +diff --git a/mDNSPosix/mDNSUNP.c b/mDNSPosix/mDNSUNP.c +index b392fc7..9f85e0e 100755 +--- a/mDNSPosix/mDNSUNP.c ++++ b/mDNSPosix/mDNSUNP.c +@@ -61,154 +61,86 @@ + #endif + + #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX +-#include +-#include +- +-/* Converts a prefix length to IPv6 network mask */ +-void plen_to_mask(int plen, char *addr) { +- int i; +- int colons=7; /* Number of colons in IPv6 address */ +- int bits_in_block=16; /* Bits per IPv6 block */ +- for(i=0; i<=colons; i++) { +- int block, ones=0xffff, ones_in_block; +- if (plen>bits_in_block) ones_in_block=bits_in_block; +- else ones_in_block=plen; +- block = ones & (ones << (bits_in_block-ones_in_block)); +- i==0 ? sprintf(addr, "%x", block) : sprintf(addr, "%s:%x", addr, block); +- plen -= ones_in_block; +- } +-} ++#include ++#include ++ + +-/* Gets IPv6 interface information from the /proc filesystem in linux*/ +-struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases) ++/* Correct way to deal with this is just to use getifaddrs (glibc ++ * 2.3.3+ and various BSDs, but BSDs are 'slightly different' just to ++ * make life interesting). We assume Linux getifaddrs is available, ++ * and if not, please upgrade. */ ++struct ifi_info *get_ifi_info_linuxv6(int doaliases) + { +- struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr; +- FILE *fp; +- char addr[8][5]; +- int flags, myflags, index, plen, scope; +- char ifname[9], lastname[IFNAMSIZ]; +- char addr6[32+7+1]; /* don't forget the seven ':' */ +- struct addrinfo hints, *res0; +- struct sockaddr_in6 *sin6; +- struct in6_addr *addrptr; +- int err; +- int sockfd = -1; +- struct ifreq ifr; +- +- res0=NULL; +- ifihead = NULL; +- ifipnext = &ifihead; +- lastname[0] = 0; ++ struct ifaddrs *ifap, *ifa; ++ struct ifi_info *ifi = NULL, *head = NULL; + +- if ((fp = fopen(PROC_IFINET6_PATH, "r")) != NULL) { +- sockfd = socket(AF_INET6, SOCK_DGRAM, 0); +- if (sockfd < 0) { +- goto gotError; ++ /* doaliases seems always true in the calls in current code */ ++ assert(doaliases); ++ ++ if (getifaddrs(&ifap) < 0) ++ { ++ return NULL; ++ } ++ for (ifa = ifap ; ifa ; ifa = ifa->ifa_next) ++ { ++ /* Care only about IPv6 addresses on non-point-to-point links. */ ++ if (!ifa->ifa_addr ++ || ifa->ifa_addr->sa_family != AF_INET6) ++ continue; ++ ifi = calloc(1, sizeof(*ifi)); ++ if (!ifi) ++ break; ++ strncpy(ifi->ifi_name, ifa->ifa_name, IFI_NAME); ++ /* We ignore ifi_{haddr,hlen}, everyone else does too */ ++ ifi->ifi_flags = ifa->ifa_flags; ++ /* We ignore ifi_myflags; IFI_ALIAS isn't used anywhere */ ++ ifi->ifi_index = if_nametoindex(ifa->ifa_name); ++ if (!(ifi->ifi_addr = malloc(sizeof(struct sockaddr_in6)))) ++ break; ++ memcpy(ifi->ifi_addr, ifa->ifa_addr, sizeof(struct sockaddr_in6)); ++ ++ if (ifa->ifa_netmask) ++ { ++ if (!(ifi->ifi_netmask = malloc(sizeof(struct sockaddr_in6)))) ++ break; ++ memcpy(ifi->ifi_netmask, ifa->ifa_netmask, ++ sizeof(struct sockaddr_in6)); + } +- while (fscanf(fp, +- "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %8s\n", +- addr[0],addr[1],addr[2],addr[3], +- addr[4],addr[5],addr[6],addr[7], +- &index, &plen, &scope, &flags, ifname) != EOF) { +- +- myflags = 0; +- if (strncmp(lastname, ifname, IFNAMSIZ) == 0) { +- if (doaliases == 0) +- continue; /* already processed this interface */ +- myflags = IFI_ALIAS; +- } +- memcpy(lastname, ifname, IFNAMSIZ); +- ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info)); +- if (ifi == NULL) { +- goto gotError; +- } + +- ifipold = *ifipnext; /* need this later */ +- ifiptr = ifipnext; +- *ifipnext = ifi; /* prev points to this new one */ +- ifipnext = &ifi->ifi_next; /* pointer to next one goes here */ +- +- sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s", +- addr[0],addr[1],addr[2],addr[3], +- addr[4],addr[5],addr[6],addr[7]); +- +- /* Add address of the interface */ +- memset(&hints, 0, sizeof(hints)); +- hints.ai_family = AF_INET6; +- hints.ai_flags = AI_NUMERICHOST; +- err = getaddrinfo(addr6, NULL, &hints, &res0); +- if (err) { +- goto gotError; +- } +- ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6)); +- if (ifi->ifi_addr == NULL) { +- goto gotError; +- } +- memcpy(ifi->ifi_addr, res0->ai_addr, sizeof(struct sockaddr_in6)); ++ if (!(ifi->ifi_addr = malloc(sizeof(struct sockaddr_in6)))) ++ break; ++ memcpy(ifi->ifi_addr, ifa->ifa_addr, sizeof(struct sockaddr_in6)); + +- /* Add netmask of the interface */ +- char ipv6addr[INET6_ADDRSTRLEN]; +- plen_to_mask(plen, ipv6addr); +- ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6)); +- if (ifi->ifi_addr == NULL) { +- goto gotError; +- } +- sin6=calloc(1, sizeof(struct sockaddr_in6)); +- addrptr=calloc(1, sizeof(struct in6_addr)); +- inet_pton(family, ipv6addr, addrptr); +- sin6->sin6_family=family; +- sin6->sin6_addr=*addrptr; +- sin6->sin6_scope_id=scope; +- memcpy(ifi->ifi_netmask, sin6, sizeof(struct sockaddr_in6)); +- free(sin6); +- +- +- /* Add interface name */ +- memcpy(ifi->ifi_name, ifname, IFI_NAME); +- +- /* Add interface index */ +- ifi->ifi_index = index; +- +- /* Add interface flags*/ +- memcpy(ifr.ifr_name, ifname, IFNAMSIZ); +- if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) { +- if (errno == EADDRNOTAVAIL) { +- /* +- * If the main interface is configured with no IP address but +- * an alias interface exists with an IP address, you get +- * EADDRNOTAVAIL for the main interface +- */ +- free(ifi->ifi_addr); +- free(ifi); +- ifipnext = ifiptr; +- *ifipnext = ifipold; +- continue; +- } else { +- goto gotError; +- } +- } +- ifi->ifi_flags = ifr.ifr_flags; +- freeaddrinfo(res0); +- res0=NULL; +- } +- } +- goto done; + +-gotError: +- if (ifihead != NULL) { +- free_ifi_info(ifihead); +- ifihead = NULL; +- } +- if (res0 != NULL) { +- freeaddrinfo(res0); +- res0=NULL; +- } +-done: +- if (sockfd != -1) { +- assert(close(sockfd) == 0); ++ if (ifa->ifa_flags & IFF_POINTOPOINT && ifa->ifa_dstaddr) ++ { ++ if (!(ifi->ifi_dstaddr = malloc(sizeof(struct sockaddr_in6)))) ++ break; ++ memcpy(ifi->ifi_dstaddr, ifa->ifa_dstaddr, ++ sizeof(struct sockaddr_in6)); ++ } ++ else if (ifa->ifa_broadaddr) ++ { ++ if (!(ifi->ifi_brdaddr = malloc(sizeof(struct sockaddr_in6)))) ++ break; ++ memcpy(ifi->ifi_brdaddr, ifa->ifa_broadaddr, ++ sizeof(struct sockaddr_in6)); ++ } ++ ifi->ifi_next = head; ++ head = ifi; ++ ifi = NULL; ++ }; ++ if (ifi) ++ { ++ /* An error occurred. Let's bail out. */ ++ ifi->ifi_next = head; ++ free_ifi_info(head); ++ return NULL; + } +- return(ifihead); /* pointer to first structure in linked list */ ++ freeifaddrs(ifap); ++ return head; + } ++ + #endif // defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX + + struct ifi_info *get_ifi_info(int family, int doaliases) +@@ -229,7 +161,7 @@ struct ifi_info *get_ifi_info(int family, int doaliases) + #endif + + #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX +- if (family == AF_INET6) return get_ifi_info_linuxv6(family, doaliases); ++ if (family == AF_INET6) return get_ifi_info_linuxv6(doaliases); + #endif + + sockfd = -1; +diff --git a/mDNSPosix/mDNSUNP.h b/mDNSPosix/mDNSUNP.h +index cc81b7d..e710087 100755 +--- a/mDNSPosix/mDNSUNP.h ++++ b/mDNSPosix/mDNSUNP.h +@@ -97,8 +97,7 @@ struct ifi_info { + }; + + #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX +-#define PROC_IFINET6_PATH "/proc/net/if_inet6" +-extern struct ifi_info *get_ifi_info_linuxv6(int family, int doaliases); ++extern struct ifi_info *get_ifi_info_linuxv6(int doaliases); + #endif + + #if defined(AF_INET6) && HAVE_IPV6 +diff --git a/mDNSShared/dnsextd_parser.y b/mDNSShared/dnsextd_parser.y +index 18c5990..d4b63ce 100644 +--- a/mDNSShared/dnsextd_parser.y ++++ b/mDNSShared/dnsextd_parser.y +@@ -15,6 +15,8 @@ + * limitations under the License. + */ + ++%parse-param { void *context } ++ + %{ + #include + #include +@@ -23,7 +25,7 @@ + #include "DebugServices.h" + #include "dnsextd.h" + +-void yyerror( const char* error ); ++void yyerror( void *context, const char* error ); + int yylex(void); + + +@@ -378,7 +380,7 @@ int yywrap(void); + + extern int yylineno; + +-void yyerror( const char *str ) ++void yyerror( void *context, const char *str ) + { + fprintf( stderr,"%s:%d: error: %s\n", g_filename, yylineno, str ); + }