From 00028b6b41d90462e4e156813778155675e9628c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 8 Feb 2007 16:42:22 +0000 Subject: FreeBSD portability (Patch from Bruce M Simpson) git-svn-id: file:///home/lennart/svn/public/nss-mdns/trunk@114 0ee8848e-81ea-0310-a63a-f631d1a40d77 --- configure.ac | 7 + doc/README.html.in | 2 + src/Makefile.am | 66 ++++++-- src/avahi-test.c | 1 + src/bsdnss.c | 467 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/query.c | 89 ++++++++-- 6 files changed, 600 insertions(+), 32 deletions(-) create mode 100644 src/bsdnss.c diff --git a/configure.ac b/configure.ac index 0cd6c3a..8592c2f 100644 --- a/configure.ac +++ b/configure.ac @@ -83,6 +83,13 @@ AC_FUNC_MALLOC AC_FUNC_SELECT_ARGTYPES AC_CHECK_FUNCS([gethostbyaddr gethostbyname gettimeofday inet_ntoa memset select socket strcspn strdup strerror strncasecmp strcasecmp strspn]) +# FreeBSD has a slightly different NSS interface +case ${host} in + *-freebsd*) freebsd="yes" ;; +esac + +AM_CONDITIONAL([FREEBSD_NSS], [test "x$freebsd" = "xyes"]) + # If using GCC specify some additional parameters if test "x$GCC" = "xyes" ; then CFLAGS="$CFLAGS -pipe -W -Wall -pedantic" diff --git a/doc/README.html.in b/doc/README.html.in index 2bfc24f..1c796ad 100644 --- a/doc/README.html.in +++ b/doc/README.html.in @@ -284,6 +284,8 @@ compilation and make install (as root) for installation of

Philipp Zabel for ARM support.

+

Bruce M Simpson for porting it to FreeBSD.

+

Download

The newest release is always available from @PACKAGE_URL@

diff --git a/src/Makefile.am b/src/Makefile.am index c2c2c94..b770559 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -29,39 +29,46 @@ AM_CFLAGS = \ # This cool debug trap works on i386/gcc only AM_CFLAGS+='-DDEBUG_TRAP=__asm__("int $$3")' -lib_LTLIBRARIES= \ +AM_LDFLAGS=-avoid-version -module -export-dynamic + +lib_LTLIBRARIES = + +if FREEBSD_NSS +lib_LTLIBRARIES += \ + nss_mdns.la \ + nss_mdns4.la \ + nss_mdns6.la \ + nss_mdns_minimal.la \ + nss_mdns4_minimal.la \ + nss_mdns6_minimal.la +else +lib_LTLIBRARIES += \ libnss_mdns.la \ libnss_mdns4.la \ libnss_mdns6.la \ libnss_mdns_minimal.la \ libnss_mdns4_minimal.la \ libnss_mdns6_minimal.la +endif -noinst_PROGRAMS= \ - nss-test - -libnss_mdns_la_SOURCES= \ - nss.c \ - util.c util.h - -libnss_mdns_la_CFLAGS=$(AM_CFLAGS) -libnss_mdns_la_LDFLAGS=-avoid-version -module -export-dynamic -shrext .so.2 -Wl,-version-script=$(srcdir)/map-file +noinst_PROGRAMS = nss-test +sources = util.c util.h if ENABLE_AVAHI -libnss_mdns_la_SOURCES += \ - avahi.c avahi.h - +sources += avahi.c avahi.h noinst_PROGRAMS += avahi-test endif if ENABLE_LEGACY -libnss_mdns_la_SOURCES += \ - query.c query.h \ - dns.c dns.h - +sources += query.c query.h dns.c dns.h noinst_PROGRAMS += mdns-test endif +# GNU Libc +libnss_mdns_la_SOURCES= $(sources) nss.c +libnss_mdns_la_CFLAGS=$(AM_CFLAGS) +libnss_mdns_la_LDFLAGS=$(AM_LDFLAGS) -shrext .so.2 -Wl,-version-script=$(srcdir)/map-file + libnss_mdns_minimal_la_SOURCES=$(libnss_mdns_la_SOURCES) libnss_mdns_minimal_la_CFLAGS=$(libnss_mdns_la_CFLAGS) -DMDNS_MINIMAL libnss_mdns_minimal_la_LDFLAGS=$(libnss_mdns_la_LDFLAGS) @@ -82,6 +89,31 @@ libnss_mdns6_minimal_la_SOURCES=$(libnss_mdns_la_SOURCES) libnss_mdns6_minimal_la_CFLAGS=$(libnss_mdns_la_CFLAGS) -DNSS_IPV6_ONLY=1 -DMDNS_MINIMAL libnss_mdns6_minimal_la_LDFLAGS=$(libnss_mdns_la_LDFLAGS) +# FreeBSD +nss_mdns_la_SOURCES=$(sources) bsdnss.c +nss_mdns_la_CFLAGS=$(AM_CFLAGS) +nss_mdns_la_LDFLAGS=$(AM_LDFLAGS) -shrext .so.1 + +nss_mdns_minimal_la_SOURCES=$(nss_mdns_la_SOURCES) +nss_mdns_minimal_la_CFLAGS=$(nss_mdns_la_CFLAGS) -DMDNS_MINIMAL +nss_mdns_minimal_la_LDFLAGS=$(nss_mdns_la_LDFLAGS) + +nss_mdns4_la_SOURCES=$(nss_mdns_la_SOURCES) +nss_mdns4_la_CFLAGS=$(nss_mdns_la_CFLAGS) -DNSS_IPV4_ONLY=1 +nss_mdns4_la_LDFLAGS=$(nss_mdns_la_LDFLAGS) + +nss_mdns4_minimal_la_SOURCES=$(nss_mdns_la_SOURCES) +nss_mdns4_minimal_la_CFLAGS=$(nss_mdns_la_CFLAGS) -DNSS_IPV4_ONLY=1 -DMDNS_MINIMAL +nss_mdns4_minimal_la_LDFLAGS=$(nss_mdns_la_LDFLAGS) + +nss_mdns6_la_SOURCES=$(nss_mdns_la_SOURCES) +nss_mdns6_la_CFLAGS=$(nss_mdns_la_CFLAGS) -DNSS_IPV6_ONLY=1 +nss_mdns6_la_LDFLAGS=$(nss_mdns_la_LDFLAGS) + +nss_mdns6_minimal_la_SOURCES=$(nss_mdns_la_SOURCES) +nss_mdns6_minimal_la_CFLAGS=$(nss_mdns_la_CFLAGS) -DNSS_IPV6_ONLY=1 -DMDNS_MINIMAL +nss_mdns6_minimal_la_LDFLAGS=$(nss_mdns_la_LDFLAGS) + avahi_test_SOURCES = \ avahi.c avahi.h \ util.c util.h \ diff --git a/src/avahi-test.c b/src/avahi-test.c index b1be16d..e57d8b2 100644 --- a/src/avahi-test.c +++ b/src/avahi-test.c @@ -19,6 +19,7 @@ USA. ***/ +#include #include #include diff --git a/src/bsdnss.c b/src/bsdnss.c new file mode 100644 index 0000000..cdda366 --- /dev/null +++ b/src/bsdnss.c @@ -0,0 +1,467 @@ +/* $Id$ */ + +/*** + This file is part of nss-mdns. +· + nss-mdns is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. +· + nss-mdns is distributed in the hope that it will be useful, but1 + 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 Lesser General Public License + along with nss-mdns; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +/* Original author: Bruce M. Simpson */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "config.h" + +#ifdef MDNS_MINIMAL +/* + * FreeBSD support prefers Avahi. + */ +#endif + +#if defined(NSS_IPV4_ONLY) || defined(NSS_IPV6_ONLY) +/* + * FreeBSD's libc is always built with IPv4 support. + * There is no way of telling at compile time with a define if libc + * was built with -DINET6 or not; a configure test would be required. + * Therefore, distinguishing between the two makes no sense. + */ +#define NO_BUILD_BSD_NSS +#endif + +#ifndef NO_BUILD_BSD_NSS +/* + * To turn on utrace() records, compile with -DDEBUG_UTRACE. + */ +#ifdef DEBUG_UTRACE +#define _NSS_UTRACE(msg) \ + do { \ + static const char __msg[] = msg ; \ + (void)utrace(__msg, sizeof(__msg)); \ + } while (0) +#else +#define _NSS_UTRACE(msg) +#endif + +ns_mtab *nss_module_register(const char *source, unsigned int *mtabsize, + nss_module_unregister_fn *unreg); + +extern enum nss_status _nss_mdns_gethostbyname_r (const char *name, struct hostent * result, + char *buffer, size_t buflen, int *errnop, + int *h_errnop); + +extern enum nss_status _nss_mdns_gethostbyname2_r (const char *name, int af, struct hostent * result, + char *buffer, size_t buflen, int *errnop, + int *h_errnop); +extern enum nss_status _nss_mdns_gethostbyaddr_r (struct in_addr * addr, int len, int type, + struct hostent * result, char *buffer, + size_t buflen, int *errnop, int *h_errnop); +extern enum nss_status _nss_mdns4_gethostbyname_r (const char *name, struct hostent * result, + char *buffer, size_t buflen, int *errnop, + int *h_errnop); + +extern enum nss_status _nss_mdns4_gethostbyname2_r (const char *name, int af, struct hostent * result, + char *buffer, size_t buflen, int *errnop, + int *h_errnop); +extern enum nss_status _nss_mdns4_gethostbyaddr_r (struct in_addr * addr, int len, int type, + struct hostent * result, char *buffer, + size_t buflen, int *errnop, int *h_errnop); +extern enum nss_status _nss_mdns6_gethostbyname_r (const char *name, struct hostent * result, + char *buffer, size_t buflen, int *errnop, + int *h_errnop); + +extern enum nss_status _nss_mdns6_gethostbyname2_r (const char *name, int af, struct hostent * result, + char *buffer, size_t buflen, int *errnop, + int *h_errnop); +extern enum nss_status _nss_mdns6_gethostbyaddr_r (struct in_addr * addr, int len, int type, + struct hostent * result, char *buffer, + size_t buflen, int *errnop, int *h_errnop); + +typedef enum nss_status (*_bsd_nsstub_fn_t)(const char *, struct hostent *, char *, size_t, int *, int *); + +/* XXX: FreeBSD 5.x is not supported. */ +static NSS_METHOD_PROTOTYPE(__nss_bsdcompat_getaddrinfo); +static NSS_METHOD_PROTOTYPE(__nss_bsdcompat_gethostbyaddr_r); +static NSS_METHOD_PROTOTYPE(__nss_bsdcompat_gethostbyname2_r); +static NSS_METHOD_PROTOTYPE(__nss_bsdcompat_ghbyaddr); +static NSS_METHOD_PROTOTYPE(__nss_bsdcompat_ghbyname); + +static ns_mtab methods[] = { + /* database, name, method, mdata */ + { NSDB_HOSTS, "getaddrinfo", __nss_bsdcompat_getaddrinfo, NULL }, + { NSDB_HOSTS, "gethostbyaddr_r", __nss_bsdcompat_gethostbyaddr_r, NULL }, + { NSDB_HOSTS, "gethostbyname2_r", __nss_bsdcompat_gethostbyname2_r, NULL }, + { NSDB_HOSTS, "ghbyaddr", __nss_bsdcompat_ghbyaddr, NULL }, + { NSDB_HOSTS, "ghbyname", __nss_bsdcompat_ghbyname, NULL }, +}; + +ns_mtab * +nss_module_register(const char *source, unsigned int *mtabsize, + nss_module_unregister_fn *unreg) +{ + + *mtabsize = sizeof(methods)/sizeof(methods[0]); + *unreg = NULL; + return (methods); +} + +/* + * Calling convention: + * ap: const char *name (optional), struct addrinfo *pai (hints, optional) + * retval: struct addrinfo ** + * + * TODO: Map all returned hostents, not just the first match. + * + * name must always be specified by libc; pai is allocated + * by libc and must always be specified. + * + * We can malloc() addrinfo instances and hang them off ai->next; + * canonnames may also be malloc()'d. + * libc is responsible for mapping our ns error return to gai_strerror(). + * + * libc calls us only to look up qualified hostnames. We don't need to + * worry about port numbers; libc will call getservbyname() and explore + * the appropriate maps configured in nsswitch.conf(5). + * + * _errno and _h_errno are unused by getaddrinfo(), as it is + * [mostly] OS independent interface implemented by Win32. + */ +static int +__nss_bsdcompat_getaddrinfo(void *retval, void *mdata __unused, va_list ap) +{ + struct addrinfo sentinel; + struct addrinfo *ai; + char *buffer; + void *cbufp; /* buffer handed to libc */ + char *hap; + struct hostent *hp; + void *mbufp; /* buffer handed to mdns */ + const char *name; + const struct addrinfo *pai; + struct sockaddr *psa; /* actually *sockaddr_storage */ + struct addrinfo **resultp; + int _errno; + int _h_errno; + size_t mbuflen = 1024; + enum nss_status status; + + _NSS_UTRACE("__nss_bsdcompat_getaddrinfo: called"); + + _h_errno = _errno = 0; + status = NSS_STATUS_UNAVAIL; + + name = va_arg(ap, const char *); + pai = va_arg(ap, struct addrinfo *); + resultp = (struct addrinfo **)retval; + + /* XXX: Will be used to hang off multiple matches later. */ + memset(&sentinel, 0, sizeof(sentinel)); + + if (name == NULL || pai == NULL) { + *resultp = sentinel.ai_next; + return (NS_UNAVAIL); + } + + mbufp = malloc((sizeof(struct hostent) + mbuflen)); + if (mbufp == NULL) { + *resultp = sentinel.ai_next; + return (NS_UNAVAIL); + } + hp = (struct hostent *)mbufp; + buffer = (char *)(hp + 1); + + cbufp = malloc(sizeof(struct addrinfo) + + sizeof(struct sockaddr_storage)); + if (cbufp == NULL) { + free(mbufp); + *resultp = sentinel.ai_next; + return (NS_UNAVAIL); + } + ai = (struct addrinfo *)cbufp; + psa = (struct sockaddr *)(ai + 1); + + /* + * 1. Select which function to call based on the address family. + * 2. Map hostent to addrinfo. + * 3. Hand-off buffer to libc. + */ + switch (pai->ai_family) { + case AF_UNSPEC: + status = _nss_mdns_gethostbyname_r(name, hp, buffer, mbuflen, + &_errno, &_h_errno); + break; + case AF_INET: + status = _nss_mdns4_gethostbyname_r(name, hp, buffer, mbuflen, + &_errno, &_h_errno); + break; + case AF_INET6: + status = _nss_mdns6_gethostbyname_r(name, hp, buffer, mbuflen, + &_errno, &_h_errno); + break; + default: + break; + } + status = __nss_compat_result(status, _errno); + + if (status == NS_SUCCESS) { + memset(ai, 0, sizeof(struct addrinfo)); + ai->ai_flags = pai->ai_flags; + ai->ai_socktype = pai->ai_socktype; + ai->ai_protocol = pai->ai_protocol; + ai->ai_family = hp->h_addrtype; + memset(psa, 0, sizeof(struct sockaddr_storage)); + psa->sa_len = ai->ai_addrlen; + psa->sa_family = ai->ai_family; + ai->ai_addr = psa; + hap = hp->h_addr_list[0]; + switch (ai->ai_family) { + case AF_INET: + ai->ai_addrlen = sizeof(struct sockaddr_in); + memcpy(&((struct sockaddr_in *)psa)->sin_addr, hap, + ai->ai_addrlen); + break; + case AF_INET6: + ai->ai_addrlen = sizeof(struct sockaddr_in6); + memcpy(&((struct sockaddr_in6 *)psa)->sin6_addr, hap, + ai->ai_addrlen); + break; + default: + ai->ai_addrlen = sizeof(struct sockaddr_storage); + memcpy(psa->sa_data, hap, ai->ai_addrlen); + } + sentinel.ai_next = ai; + free(mbufp); + } + + if (sentinel.ai_next == NULL) { + free(cbufp); + free(mbufp); + } + + *resultp = sentinel.ai_next; + return (status); +} + +/* + * Calling convention: + * ap: const u_char *uaddr, socklen_t len, int af, struct hostent *hp, + * char *buf, size_t buflen, int ret_errno, int *h_errnop + * retval: should be set to NULL or hp passed in + */ +static int +__nss_bsdcompat_gethostbyaddr_r(void *retval, void *mdata __unused, va_list ap) +{ + void *addr; + char *buf; + int *h_errnop; + struct hostent *hp; + struct hostent **resultp; + int af; + size_t buflen; + int len; + int ret_errno; + enum nss_status status; + + addr = va_arg(ap, void *); + len = va_arg(ap, socklen_t); + af = va_arg(ap, int); + hp = va_arg(ap, struct hostent *); + buf = va_arg(ap, char *); + buflen = va_arg(ap, size_t); + ret_errno = va_arg(ap, int); + h_errnop = va_arg(ap, int *); + resultp = (struct hostent **)retval; + + *resultp = NULL; + status = _nss_mdns_gethostbyaddr_r(addr, len, af, hp, buf, buflen, + &ret_errno, h_errnop); + + status = __nss_compat_result(status, *h_errnop); + if (status == NS_SUCCESS) + *resultp = hp; + return (status); +} + +/* + * Calling convention: + * ap: const char *name, int af, struct hostent *hp, char *buf, + * size_t buflen, int ret_errno, int *h_errnop + * retval is a struct hostent **result passed in by the libc client, + * which is responsible for allocating storage. + */ +static int +__nss_bsdcompat_gethostbyname2_r(void *retval, void *mdata __unused, + va_list ap) +{ + char *buf; + const char *name; + int *h_errnop; + struct hostent *hp; + struct hostent **resultp; + int af; + size_t buflen; + int ret_errno; + enum nss_status status; + + name = va_arg(ap, char *); + af = va_arg(ap, int); + hp = va_arg(ap, struct hostent *); + buf = va_arg(ap, char *); + buflen = va_arg(ap, size_t); + ret_errno = va_arg(ap, int); + h_errnop = va_arg(ap, int *); + resultp = (struct hostent **)retval; + + *resultp = NULL; + if (hp == NULL) + return (NS_UNAVAIL); + + status = _nss_mdns_gethostbyname2_r(name, af, hp, buf, buflen, + &ret_errno, h_errnop); + + status = __nss_compat_result(status, *h_errnop); + if (status == NS_SUCCESS) + *resultp = hp; + return (status); +} + +/* + * Used by getipnodebyaddr(3). + * + * Calling convention: + * ap: struct in[6]_addr *src, size_t len, int af, int *errp + * retval: pointer to a pointer to an uninitialized struct hostent, + * in which should be returned a single pointer to on-heap storage. + * + * This function is responsible for allocating on-heap storage. + * The caller is responsible for calling freehostent() on the returned + * storage. + */ +static int +__nss_bsdcompat_ghbyaddr(void *retval, void *mdata __unused, va_list ap) +{ + char *buffer; + void *bufp; + int *errp; + struct hostent *hp; + struct hostent **resultp; + void *src; + int af; + size_t buflen = 1024; + size_t len; + int h_errnop; + enum nss_status status; + + src = va_arg(ap, void *); + len = va_arg(ap, size_t); + af = va_arg(ap, int); + errp = va_arg(ap, int *); + resultp = (struct hostent **)retval; + + _NSS_UTRACE("__nss_bsdcompat_ghbyaddr: called"); + + bufp = malloc((sizeof(struct hostent) + buflen)); + if (bufp == NULL) { + *resultp = NULL; + return (NS_UNAVAIL); + } + hp = (struct hostent *)bufp; + buffer = (char *)(hp + 1); + + status = _nss_mdns_gethostbyaddr_r(src, len, af, hp, buffer, + buflen, errp, &h_errnop); + + status = __nss_compat_result(status, *errp); + if (status != NS_SUCCESS) { + free(bufp); + hp = NULL; + } + *resultp = hp; + return (status); +} + +/* + * Used by getipnodebyname(3). + * + * Calling convention: + * ap: const char *name, int af, int *errp + * retval: pointer to a pointer to an uninitialized struct hostent. + * + * This function is responsible for allocating on-heap storage. + * The caller is responsible for calling freehostent() on the returned + * storage. + */ +static int +__nss_bsdcompat_ghbyname(void *retval, void *mdata __unused, va_list ap) +{ + char *buffer; + void *bufp; + int *errp; + struct hostent *hp; + struct hostent **resultp; + char *name; + int af; + size_t buflen = 1024; + int h_errnop; + enum nss_status status; + + name = va_arg(ap, char *); + af = va_arg(ap, int); + errp = va_arg(ap, int *); + resultp = (struct hostent **)retval; + + bufp = malloc((sizeof(struct hostent) + buflen)); + if (bufp == NULL) { + *resultp = NULL; + return (NS_UNAVAIL); + } + hp = (struct hostent *)bufp; + buffer = (char *)(hp + 1); + + status = _nss_mdns_gethostbyname_r(name, hp, buffer, buflen, errp, + &h_errnop); + + status = __nss_compat_result(status, *errp); + if (status != NS_SUCCESS) { + free(bufp); + hp = NULL; + } + *resultp = hp; + return (status); +} + +#endif /* !NO_BUILD_BSD_NSS */ diff --git a/src/query.c b/src/query.c index fe5d541..42549bd 100644 --- a/src/query.c +++ b/src/query.c @@ -87,13 +87,36 @@ int mdns_open_socket(void) { if (bind(fd, (struct sockaddr*) &sa, sizeof(sa)) < 0) goto fail; +#ifdef IP_PKTINFO yes = 1; - if (setsockopt(fd, IPPROTO_IP, IP_RECVTTL, &yes, sizeof(yes)) < 0) - goto fail; - if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &yes, sizeof(yes)) < 0) goto fail; +#else + +#ifdef IP_RECVINTERFACE + yes = 1; + if (setsockopt (fd, IPPROTO_IP, IP_RECVINTERFACE, &yes, sizeof(yes)) < 0) + goto fail; +#elif defined(IP_RECVIF) + yes = 1; + if (setsockopt (fd, IPPROTO_IP, IP_RECVIF, &yes, sizeof(yes)) < 0) + goto fail; +#endif + +#ifdef IP_RECVDSTADDR + yes = 1; + if (setsockopt (fd, IPPROTO_IP, IP_RECVDSTADDR, &yes, sizeof(yes)) < 0) + goto fail; +#endif + +#endif /* IP_PKTINFO */ +#ifdef IP_RECVTTL + yes = 1; + if (setsockopt(fd, IPPROTO_IP, IP_RECVTTL, &yes, sizeof(yes)) < 0) + goto fail; +#endif + if (set_cloexec(fd) < 0) goto fail; @@ -113,9 +136,15 @@ static int send_dns_packet(int fd, struct dns_packet *p) { struct sockaddr_in sa; struct msghdr msg; struct iovec io; +#ifdef IP_PKTINFO struct cmsghdr *cmsg; + uint8_t cmsg_data[CMSG_SPACE(sizeof(struct in_pktinfo))]; struct in_pktinfo *pkti; - uint8_t cmsg_data[CMSG_LEN(sizeof(struct in_pktinfo))]; +#elif defined(IP_SENDSRCADDR) + struct cmsghdr *cmsg; + uint8_t cmsg_data[CMSG_SPACE(sizeof(struct in_addr))]; + struct in_addr *addr; +#endif int i, n; struct ifreq ifreq[32]; struct ifconf ifconf; @@ -131,24 +160,43 @@ static int send_dns_packet(int fd, struct dns_packet *p) { io.iov_base = p->data; io.iov_len = p->size; - memset(cmsg_data, 0, sizeof(cmsg_data)); - cmsg = (struct cmsghdr*) cmsg_data; - cmsg->cmsg_len = sizeof(cmsg_data); - cmsg->cmsg_level = IPPROTO_IP; - cmsg->cmsg_type = IP_PKTINFO; - - pkti = (struct in_pktinfo*) CMSG_DATA(cmsg); - pkti->ipi_ifindex = 0; - memset(&msg, 0, sizeof(msg)); msg.msg_name = &sa; msg.msg_namelen = sizeof(sa); msg.msg_iov = &io; msg.msg_iovlen = 1; + msg.msg_flags = 0; + +#ifdef IP_PKTINFO + memset(cmsg_data, 0, sizeof(cmsg_data)); msg.msg_control = cmsg_data; msg.msg_controllen = sizeof(cmsg_data); - msg.msg_flags = 0; + + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); + cmsg->cmsg_level = IPPROTO_IP; + cmsg->cmsg_type = IP_PKTINFO; + pkti = (struct in_pktinfo*) CMSG_DATA(cmsg); + + msg.msg_controllen = cmsg->cmsg_len; +#elif defined(IP_SENDSRCADDR) + memset(cmsg_data, 0, sizeof(cmsg_data)); + msg.msg_control = cmsg_data; + msg.msg_controllen = sizeof(cmsg_data); + + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); + cmsg->cmsg_level = IPPROTO_IP; + cmsg->cmsg_type = IP_SENDSRCADDR; + + addr = (struct in_addr *)CMSG_DATA(cmsg); + + msg.msg_controllen = cmsg->cmsg_len; +#elif defined(__GNUC__) +#warning "FIXME: We need some code to set the outgoing interface/local address here if IP_PKTINFO/IP_SENDSRCADDR is not available" +#endif + ifconf.ifc_req = ifreq; ifconf.ifc_len = sizeof(ifreq); @@ -183,6 +231,7 @@ static int send_dns_packet(int fd, struct dns_packet *p) { if (ioctl(fd, SIOCGIFINDEX, &ifreq[i]) < 0) continue; /* See above why we ignore this error */ +#ifdef IP_PKTINFO /* Only send the the packet once per interface. We assume that * multiple addresses assigned to the same interface follow * immediately one after the other.*/ @@ -190,6 +239,11 @@ static int send_dns_packet(int fd, struct dns_packet *p) { continue; last_index = pkti->ipi_ifindex = ifreq[i].ifr_ifindex; +#elif defined(IP_SENDSRCADDR) + addr->s_addr = ifsa->sin_addr.s_addr; +#elif defined(__GNUC__) +#warning "FIXME: We need some code to set the outgoing interface/local address here if IP_PKTINFO/IP_SENDSRCADDR is not available" +#endif for (;;) { @@ -241,7 +295,12 @@ static int recv_dns_packet(int fd, struct dns_packet **ret_packet, uint8_t *ret_ *ret_ttl = 0; for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg,cmsg)) { - if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_TTL) { +#ifdef SOL_IP + if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_TTL) +#else + if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_TTL) +#endif + { *ret_ttl = (uint8_t) (*(uint32_t*) CMSG_DATA(cmsg)); break; } -- cgit