Hello,
patches resolve the build failures, functionality, and performance
issues on Solaris. A brief description is included in each patch.
Please let me know whether these patches could be merged and which
changes are necessary.
Thanks.
Patches to successfully compile dnsmasq-2.76 on Solaris.
diff -r ebc8338a8ccf -r 25a63355244c src/bpf.c
--- a/src/bpf.c Fri Oct 06 14:03:20 2017 +0100
+++ b/src/bpf.c Fri Oct 06 14:04:47 2017 +0100
@@ -32,8 +32,10 @@
#endif
#include <netinet/in_var.h>
#ifdef HAVE_IPV6
+#ifndef HAVE_SOLARIS_NETWORK
# include <netinet6/in6_var.h>
#endif
+#endif
#ifndef SA_SIZE
#define SA_SIZE(sa) \
--- dnsmasq-2.80/src/config.h 2018-12-14 04:52:24.163287145 +0000
+++ dnsmasq-2.80/src/config.h 2018-12-14 04:49:29.397508965 +0000
@@ -305,7 +305,8 @@ HAVE_SOCKADDR_SA_LEN
#define HAVE_GETOPT_LONG
#undef HAVE_SOCKADDR_SA_LEN
#define ETHER_ADDR_LEN 6
-
+#undef HAVE_IPSET
+
#endif
/* Decide if we're going to support IPv6 */
--- dnsmasq-2.80/src/dnsmasq.h 2018-12-14 04:52:42.564660119 +0000
+++ dnsmasq-2.80/src/dnsmasq.h 2018-12-14 04:49:29.399869884 +0000
@@ -1354,7 +1354,7 @@ int set_ipv6pktinfo(int fd);
#ifdef HAVE_DHCP6
void join_multicast(int dienow);
#endif
-#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_BSD_NETWORK)
+#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
void newaddress(time_t now);
#endif
diff -r ebc8338a8ccf -r 25a63355244c src/ip6addr.h
--- a/src/ip6addr.h Fri Oct 06 14:03:20 2017 +0100
+++ b/src/ip6addr.h Fri Oct 06 14:04:47 2017 +0100
@@ -14,8 +14,41 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#ifdef HAVE_SOLARIS_NETWORK
+#ifdef _BIG_ENDIAN
+#define IN6_IS_ADDR_ULA(a) \
+ (((a)->_S6_un._S6_u32[0] & htonl (0x000000ff)) \
+ == htonl (0x000000fd))
+#define IN6_IS_ADDR_ULA_ZERO(a) \
+ (((a)->_S6_un._S6_u32[0] == htonl (0x000000fd)) \
+ && ((a)->_S6_un._S6_u32[1] == 0) \
+ && ((a)->_S6_un._S6_u32[2] == 0) \
+ && ((a)->_S6_un._S6_u32[3] == 0))
+#define IN6_IS_ADDR_LINK_LOCAL_ZERO(a) \
+ (((a)->_S6_un._S6_u32[0] == htonl (0x000080fe)) \
+ && ((a)->_S6_un._S6_u32[1] == 0) \
+ && ((a)->_S6_un._S6_u32[2] == 0) \
+ && ((a)->_S6_un._S6_u32[3] == 0))
+#else /* _BIG_ENDIAN */
+#define IN6_IS_ADDR_ULA(a) \
+ (((a)->_S6_un._S6_u32[0] & htonl (0xff000000)) \
+ == htonl (0xfd000000))
+
+#define IN6_IS_ADDR_ULA_ZERO(a) \
+ (((a)->_S6_un._S6_u32[0] == htonl (0xfd000000)) \
+ && ((a)->_S6_un._S6_u32[1] == 0) \
+ && ((a)->_S6_un._S6_u32[2] == 0) \
+ && ((a)->_S6_un._S6_u32[3] == 0))
+
+#define IN6_IS_ADDR_LINK_LOCAL_ZERO(a) \
+ (((a)->_S6_un._S6_u32[0] == htonl (0xfe800000)) \
+ && ((a)->_S6_un._S6_u32[1] == 0) \
+ && ((a)->_S6_un._S6_u32[2] == 0) \
+ && ((a)->_S6_un._S6_u32[3] == 0))
+#endif /* _BIG_ENDIAN */
+#else /* HAVE_SOLARIS_NETWORK */
#define IN6_IS_ADDR_ULA(a) \
((((__const uint32_t *) (a))[0] & htonl (0xff000000)) \
== htonl (0xfd000000))
@@ -31,4 +64,4 @@
&& ((__const uint32_t *) (a))[1] == 0 \
&& ((__const uint32_t *) (a))[2] == 0 \
&& ((__const uint32_t *) (a))[3] == 0)
-
+#endif /* HAVE_SOLARIS_NETWORK */
If there are multiple datalinks configured with IP addresses from the same
subnet, then the datalink to which an on-link device's ARP entry will be
associated depends on the order in which these datalinks were plumbed with
IP addresses. In that, the datalink that was plumbed for IP last will have
the ARP entry associated against it. To avoid, this we need to use
SIOCSXARP ioctl to specify the exact datalink.
diff -r 25a63355244c -r 57a8838a38db src/dhcp.c
--- a/src/dhcp.c Fri Oct 06 14:04:47 2017 +0100
+++ b/src/dhcp.c Fri Oct 06 14:07:58 2017 +0100
@@ -439,17 +439,24 @@
else
{
/* unicast to unconfigured client. Inject mac address direct into ARP cache.
- Note that this only works for ethernet on solaris, because we use SIOCSARP
- and not SIOCSXARP, which would be perfect, except that it returns ENXIO
- mysteriously. Bah. Fall back to broadcast for other net types. */
- struct arpreq req;
+ Fall back to broadcast for other net types. */
+ struct xarpreq xreq;
+ int ifnamsz = strlen(ifr.ifr_name);
+
+ dest.sin_family = AF_INET;
dest.sin_addr = mess->yiaddr;
dest.sin_port = htons(daemon->dhcp_client_port);
- *((struct sockaddr_in *)&req.arp_pa) = dest;
- req.arp_ha.sa_family = AF_UNSPEC;
- memcpy(req.arp_ha.sa_data, mess->chaddr, mess->hlen);
- req.arp_flags = ATF_COM;
- ioctl(daemon->dhcpfd, SIOCSARP, &req);
+ *((struct sockaddr_in *)&xreq.xarp_pa) = dest;
+ xreq.xarp_ha.sdl_nlen = ifnamsz;
+ memcpy(xreq.xarp_ha.sdl_data, ifr.ifr_name, ifnamsz);
+ xreq.xarp_ha.sdl_family = AF_LINK;
+ xreq.xarp_ha.sdl_index = iface_index;
+ /* 6 corresponds to IFT_ETHER */
+ xreq.xarp_ha.sdl_type = 6;
+ xreq.xarp_ha.sdl_alen = ETHER_ADDR_LEN;
+ memcpy(xreq.xarp_ha.sdl_data + ifnamsz, mess->chaddr, mess->hlen);
+ xreq.xarp_flags = ATF_COM;
+ ioctl(daemon->dhcpfd, SIOCSXARP, &xreq);
}
#elif defined(HAVE_BSD_NETWORK)
else
Add hooks to compile contrib/lease-tools/dhcp_release.c. This utility is used to
send a DHCPRELEASE message to tell the local DHCP server to delete a
particular lease.
Solaris doesn't support AF_NETLINK, so use getifaddrs() to determine the
IP address of an interface on which Dnsmasq process is listening.
--- dnsmasq-2.80/Makefile 2018-12-14 05:22:38.586058360 +0000
+++ dnsmasq-2.80/Makefile 2018-12-14 05:21:44.034550056 +0000
@@ -19,6 +19,7 @@
# Variables you may well want to override.
PREFIX = /usr/local
+LIBDIR = $(PREFIX)/lib/inet
BINDIR = $(PREFIX)/sbin
MANDIR = $(PREFIX)/share/man
LOCALEDIR = $(PREFIX)/share/locale
@@ -43,6 +44,7 @@ XGETTEXT = xgettext
SRC = src
PO = po
MAN = man
+LEASE_TOOLS = contrib/lease-tools
#################################################################
@@ -79,6 +81,8 @@ objs = cache.o rfc1035.o util.o option.o
domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \
poll.o rrfilter.o edns0.o arp.o crypto.o dump.o ubus.o metrics.o
+dhcp_release_objs = dhcp_release.o
+
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
dns-protocol.h radv-protocol.h ip6addr.h metrics.h
@@ -87,11 +91,12 @@ all : $(BUILDDIR)
top="$(top)" \
build_cflags="$(version) $(dbus_cflags) $(idn2_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags)" \
build_libs="$(dbus_libs) $(idn2_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs) $(ubus_libs)" \
- -f $(top)/Makefile dnsmasq
+ -f $(top)/Makefile dnsmasq dhcp_release
mostly_clean :
rm -f $(BUILDDIR)/*.mo $(BUILDDIR)/*.pot
- rm -f $(BUILDDIR)/.copts_* $(BUILDDIR)/*.o $(BUILDDIR)/dnsmasq.a $(BUILDDIR)/dnsmasq
+ rm -f $(BUILDDIR)/.copts_* $(BUILDDIR)/*.o $(BUILDDIR)/dnsmasq.a $(BUILDDIR)/dnsmasq \
+ $(BUILDDIR)/dhcp_release
clean : mostly_clean
rm -f $(BUILDDIR)/dnsmasq_baseline
@@ -103,8 +108,10 @@ install : all install-common
install-common :
$(INSTALL) -d $(DESTDIR)$(BINDIR)
$(INSTALL) -d $(DESTDIR)$(MANDIR)/man8
+ $(INSTALL) -d $(DESTDIR)/$(LIBDIR)
$(INSTALL) -m 644 $(MAN)/dnsmasq.8 $(DESTDIR)$(MANDIR)/man8
$(INSTALL) -m 755 $(BUILDDIR)/dnsmasq $(DESTDIR)$(BINDIR)
+ $(INSTALL) -m 755 $(BUILDDIR)/dhcp_release $(DESTDIR)$(LIBDIR)
all-i18n : $(BUILDDIR)
@cd $(BUILDDIR) && $(MAKE) \
@@ -112,7 +119,7 @@ all-i18n : $(BUILDDIR)
i18n=-DLOCALEDIR=\'\"$(LOCALEDIR)\"\' \
build_cflags="$(version) $(dbus_cflags) $(idn2_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags)" \
build_libs="$(dbus_libs) $(idn2_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs)" \
- -f $(top)/Makefile dnsmasq
+ -f $(top)/Makefile dnsmasq dhcp_release
for f in `cd $(PO); echo *.po`; do \
cd $(top) && cd $(BUILDDIR) && $(MAKE) top="$(top)" -f $(top)/Makefile $${f%.po}.mo; \
done
@@ -155,6 +162,9 @@ $(copts_conf): $(hdrs)
$(objs:.o=.c) $(hdrs):
ln -s $(top)/$(SRC)/$@ .
+$(dhcp_release_objs:.o=.c):
+ ln -s $(top)/$(LEASE_TOOLS)/$@ .
+
$(objs): $(copts_conf) $(hdrs)
.c.o:
@@ -163,6 +173,9 @@ $(objs): $(copts_conf) $(hdrs)
dnsmasq : $(objs)
$(CC) $(LDFLAGS) -o $@ $(objs) $(build_libs) $(LIBS)
+dhcp_release : $(objs) $(dhcp_release_objs)
+ $(CC) $(LDFLAGS) -o $@ $(dhcp_release_objs) $(build_libs) $(LIBS)
+
dnsmasq.pot : $(objs:.o=.c) $(hdrs)
$(XGETTEXT) -d dnsmasq --foreign-user --omit-header --keyword=_ -o $@ -i $(objs:.o=.c)
--- dnsmasq-2.80/contrib/lease-tools/dhcp_release.c 2018-12-14 05:23:02.690783450 +0000
+++ dnsmasq-2.80/contrib/lease-tools/dhcp_release.c 2018-12-14 05:10:55.381820113 +0000
@@ -33,6 +33,10 @@
The client-id is optional. If it is "*" then it treated as being missing.
*/
+#if defined(__sun) || defined(__sun__)
+#define HAVE_SOLARIS_NETWORK
+#endif
+
#include <sys/types.h>
#include <netinet/in.h>
#include <net/if.h>
@@ -44,9 +48,13 @@
#include <stdlib.h>
#include <net/if_arp.h>
#include <sys/ioctl.h>
+#ifdef HAVE_SOLARIS_NETWORK
+#include <ifaddrs.h>
+#else
#include <linux/types.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
+#endif
#include <errno.h>
#define DHCP_CHADDR_MAX 16
@@ -73,6 +81,7 @@ struct dhcp_packet {
unsigned char options[308];
};
+#if !defined(HAVE_SOLARIS_NETWORK)
static struct iovec iov;
static int expand_buf(struct iovec *iov, size_t size)
@@ -139,6 +148,8 @@ static ssize_t netlink_recv(int fd)
return rc;
}
+#endif
+
static int parse_hex(char *in, unsigned char *out, int maxlen, int *mac_type)
{
int i = 0;
@@ -178,6 +189,7 @@ static int is_same_net(struct in_addr a,
return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
}
+#if !defined(HAVE_SOLARIS_NETWORK)
static struct in_addr find_interface(struct in_addr client, int fd, unsigned int index)
{
struct sockaddr_nl addr;
@@ -244,6 +256,7 @@ static struct in_addr find_interface(str
exit(0);
}
+#endif
int main(int argc, char **argv)
{
@@ -254,7 +267,11 @@ int main(int argc, char **argv)
struct sockaddr_in dest;
struct ifreq ifr;
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+#ifdef HAVE_SOLARIS_NETWORK
+ int nl = 0;
+#else
int nl = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+#endif
if (argc < 4 || argc > 5)
{
@@ -267,7 +284,8 @@ int main(int argc, char **argv)
perror("cannot create socket");
exit(1);
}
-
+
+#if !defined(HAVE_SOLARIS_NETWORK)
/* This voodoo fakes up a packet coming from the correct interface, which really matters for
a DHCP server */
strncpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name)-1);
@@ -277,6 +295,7 @@ int main(int argc, char **argv)
perror("cannot setup interface");
exit(1);
}
+#endif
if (inet_addr(argv[2]) == INADDR_NONE)
{
@@ -285,8 +304,40 @@ int main(int argc, char **argv)
}
lease.s_addr = inet_addr(argv[2]);
+#ifdef HAVE_SOLARIS_NETWORK
+ struct ifaddrs *ifp_head, *ifp;
+
+ if (getifaddrs(&ifp_head) < 0)
+ {
+ perror("could not retrieve IP addresses");
+ exit(1);
+ }
+ for (ifp = ifp_head; ifp != NULL; ifp = ifp->ifa_next) {
+ if (ifp->ifa_addr->sa_family != AF_INET)
+ continue;
+ if (strcmp(ifp->ifa_name, argv[1]) == 0 &&
+ is_same_net(lease, ((struct sockaddr_in *)ifp->ifa_addr)->sin_addr,
+ ((struct sockaddr_in *)ifp->ifa_netmask)->sin_addr))
+ break;
+ }
+ if (ifp == NULL) {
+ freeifaddrs(ifp_head);
+ exit(0);
+ }
+ memcpy(&server, &((struct sockaddr_in *)ifp->ifa_addr)->sin_addr,
+ sizeof(server));
+ /* bind to the socket */
+ if (bind(fd, ifp->ifa_addr, sizeof(struct sockaddr_in)) == -1)
+ {
+ freeifaddrs(ifp_head);
+ perror("cannot bind to socket");
+ exit(1);
+ }
+ freeifaddrs(ifp_head);
+#else
server = find_interface(lease, nl, if_nametoindex(argv[1]));
-
+#endif
+
memset(&packet, 0, sizeof(packet));
packet.hlen = parse_hex(argv[3], packet.chaddr, DHCP_CHADDR_MAX, &mac_type);
Solaris doesn't have an easy way to retrieve the MAC address of the client
that is soliciting the DHCPv6 IP address. This fix uses a simple way to
retrieve the client MAC address from the client's EUI64 link-local address.
diff -r 8321d0a2d109 -r 37614cb705be src/dhcp6.c
--- a/src/dhcp6.c Fri Oct 06 14:09:33 2017 +0100
+++ b/src/dhcp6.c Fri Oct 06 14:10:20 2017 +0100
@@ -252,6 +252,23 @@
void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsigned int *maclenp, unsigned int *mactypep, time_t now)
{
+#ifdef HAVE_SOLARIS_NETWORK
+/* Solaris does not have an easy way to retrieve MAC address for a given IPv6 address from the kernel.
+ For now the following workaround should work for OpenStack's needs. */
+ uint8_t *addr6;
+
+ *maclenp = ETHER_ADDR_LEN;
+ *mactypep = ARPHRD_ETHER;
+ /* Take the EUI64 based client's link-local address and convert it to client's MAC address.
+ For example: from fe80::f816:3eff:fe5c:df43 link-local address we arrive at fa:16:3e:5c:df:43 */
+ addr6 = client->s6_addr;
+ mac[0] = addr6[8] ^ 0x2;
+ mac[1] = addr6[9];
+ mac[2] = addr6[10];
+ mac[3] = addr6[13];
+ mac[4] = addr6[14];
+ mac[5]= addr6[15];
+#else
/* Receiving a packet from a host does not populate the neighbour
cache, so we send a neighbour discovery request if we can't
find the sender. Repeat a few times in case of packet loss. */
@@ -292,6 +309,7 @@
*maclenp = maclen;
*mactypep = ARPHRD_ETHER;
+#endif /* HAVE_SOLARIS_NETWORK */
}
static int complete_context6(struct in6_addr *local, int prefix,
Patch to address a scalability issue when using dnsmasq in Openstack,
that causes DHCP to be extremely slow.
diff -r 37614cb705be -r 4468e42e6443 src/dhcp-common.c
--- a/src/dhcp-common.c Fri Oct 06 14:10:20 2017 +0100
+++ b/src/dhcp-common.c Fri Oct 06 14:11:14 2017 +0100
@@ -493,6 +493,58 @@
errno != EPERM)
die(_("failed to set SO_BINDTODEVICE on DHCP socket: %s"), NULL, EC_BADNET);
}
+#elif defined(HAVE_SOLARIS_NETWORK)
+int which_ifindex(void)
+{
+ /* If we are doing DHCP on exactly one interface, and using Solaris, we want
+ * to limit packet transmission/reception to that interface using IP_BOUND_IF
+ * for IPv4 and IPV6_BOUND_IF for IPv6. This is for the use case of OpenStack,
+ * which runs a new dnsmasq instance for each network it creates. Without this
+ * socket option, each of the dnsmasq process would unnecessarily process
+ * packets that arrive on other interfaces as well, thus slowing down the
+ * entire DHCP process.
+ */
+
+ struct irec *iface, *found;
+ struct iname *if_tmp;
+
+ if (!daemon->if_names)
+ return -1;
+
+ for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
+ if (if_tmp->name && (!if_tmp->used || strchr(if_tmp->name, '*')))
+ return -1;
+
+ for (found = NULL, iface = daemon->interfaces; iface; iface = iface->next)
+ if (iface->dhcp_ok)
+ {
+ if (!found)
+ found = iface;
+ else if (strcmp(found->name, iface->name) != 0)
+ return -1; /* more than one. */
+ }
+
+ if (found)
+ return found->index;
+
+ return -1;
+}
+
+void bindtoif(int ifindex, int fd, int is_dhcp6)
+{
+ if (is_dhcp6)
+ {
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_BOUND_IF, (char *)&ifindex, sizeof(ifindex)) == -1 &&
+ errno != EPERM)
+ die(_("failed to set IPv6_BOUND_IF on DHCP socket: %s"), NULL, EC_BADNET);
+ }
+ else
+ {
+ if (setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &ifindex, sizeof(ifindex)) == -1 &&
+ errno != EPERM)
+ die(_("failed to set IP_BOUND_IF on DHCP socket: %s"), NULL, EC_BADNET);
+ }
+}
#endif
static const struct opttab_t {
--- dnsmasq-2.80/src/dnsmasq.c 2018-12-14 05:28:46.339028699 +0000
+++ dnsmasq-2.80/src/dnsmasq.c 2018-12-14 05:27:58.711961389 +0000
@@ -55,6 +55,10 @@ int main (int argc, char **argv)
char *bound_device = NULL;
int did_bind = 0;
#endif
+#if defined(HAVE_SOLARIS_NETWORK)
+ int bound_ifindex = -1;
+ int did_bind = 0;
+#endif
#if defined(HAVE_DHCP) || defined(HAVE_DHCP6)
struct dhcp_context *context;
struct dhcp_relay *relay;
@@ -340,6 +344,23 @@ int main (int argc, char **argv)
did_bind = 1;
}
}
+#elif defined(HAVE_SOLARIS_NETWORK) && defined(HAVE_DHCP)
+ bound_ifindex = which_ifindex();
+
+ if (daemon->dhcp)
+ {
+ if (!daemon->relay4 && bound_ifindex >= 0)
+ {
+ bindtoif(bound_ifindex, daemon->dhcpfd, 0);
+ did_bind = 1;
+ }
+
+ if (daemon->enable_pxe && bound_ifindex >= 0)
+ {
+ bindtoif(bound_ifindex, daemon->pxefd, 0);
+ did_bind = 1;
+ }
+ }
#endif
#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP6)
@@ -348,6 +369,12 @@ int main (int argc, char **argv)
bindtodevice(bound_device, daemon->dhcp6fd);
did_bind = 1;
}
+#elif defined(HAVE_SOLARIS_NETWORK) && defined(HAVE_DHCP6)
+ if (daemon->doing_dhcp6 && !daemon->relay6 && bound_ifindex >= 0)
+ {
+ bindtoif(bound_ifindex, daemon->dhcp6fd, 1);
+ did_bind = 1;
+ }
#endif
}
else
@@ -868,6 +895,9 @@ int main (int argc, char **argv)
# ifdef HAVE_LINUX_NETWORK
if (did_bind)
my_syslog(MS_DHCP | LOG_INFO, _("DHCP, sockets bound exclusively to interface %s"), bound_device);
+# elif defined(HAVE_SOLARIS_NETWORK)
+ if (did_bind)
+ my_syslog(MS_DHCP | LOG_INFO, _("DHCP, sockets bound exclusively to interface index %d"), bound_ifindex);
# endif
/* after dhcp_construct_contexts */
--- dnsmasq-2.80/src/dnsmasq.h 2018-12-14 05:28:53.925237515 +0000
+++ dnsmasq-2.80/src/dnsmasq.h 2018-12-14 05:27:58.713977461 +0000
@@ -1567,6 +1567,9 @@ int config_has_mac(struct dhcp_config *c
#ifdef HAVE_LINUX_NETWORK
char *whichdevice(void);
void bindtodevice(char *device, int fd);
+#elif defined(HAVE_SOLARIS_NETWORK)
+int which_ifindex(void);
+void bindtoif(int ifindex, int fd, int is_dhcp6);
#endif
# ifdef HAVE_DHCP6
void display_opts6(void);
_______________________________________________
Dnsmasq-discuss mailing list
Dnsmasq-discuss@lists.thekelleys.org.uk
http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss