summaryrefslogtreecommitdiff
path: root/usr
diff options
context:
space:
mode:
Diffstat (limited to 'usr')
-rw-r--r--usr/src/boot/Makefile.version2
-rw-r--r--usr/src/boot/lib/libstand/zfs/zfsimpl.c15
-rw-r--r--usr/src/cmd/Makefile1
-rw-r--r--usr/src/cmd/cmd-inet/usr.bin/dns-sd/Makefile2
-rw-r--r--usr/src/cmd/cmd-inet/usr.bin/rdist/server.c220
-rw-r--r--usr/src/cmd/cmd-inet/usr.lib/mdnsd/Makefile7
-rw-r--r--usr/src/cmd/nvmeadm/Makefile4
-rw-r--r--usr/src/cmd/nvmeadm/nvmeadm.c155
-rw-r--r--usr/src/cmd/nvmeadm/nvmeadm.h30
-rw-r--r--usr/src/cmd/nvmeadm/nvmeadm_ofmt.c132
-rw-r--r--usr/src/cmd/nvmeadm/nvmeadm_print.c6
-rw-r--r--usr/src/cmd/pcieadm/Makefile45
-rw-r--r--usr/src/cmd/pcieadm/pcieadm.c624
-rw-r--r--usr/src/cmd/pcieadm/pcieadm.h112
-rw-r--r--usr/src/cmd/pcieadm/pcieadm_cfgspace.c5046
-rw-r--r--usr/src/cmd/pcieadm/pcieadm_devs.c568
-rw-r--r--usr/src/cmd/sendmail/src/daemon.c3
-rw-r--r--usr/src/cmd/sgs/elfdump/Makefile.com2
-rw-r--r--usr/src/cmd/sgs/libld/common/syms.c15
-rw-r--r--usr/src/cmd/sgs/libld/common/update.c4
-rw-r--r--usr/src/cmd/sgs/tools/Makefile.com2
-rw-r--r--usr/src/cmd/sgs/tools/SUNWonld-README1
-rw-r--r--usr/src/contrib/mDNSResponder/Clients/dns-sd.c442
-rw-r--r--usr/src/contrib/mDNSResponder/README9
-rw-r--r--usr/src/contrib/mDNSResponder/mDNSCore/CryptoAlg.c280
-rw-r--r--usr/src/contrib/mDNSResponder/mDNSCore/CryptoAlg.h62
-rw-r--r--usr/src/contrib/mDNSResponder/mDNSCore/DNSCommon.c1205
-rw-r--r--usr/src/contrib/mDNSResponder/mDNSCore/DNSCommon.h63
-rw-r--r--usr/src/contrib/mDNSResponder/mDNSCore/DNSDigest.c79
-rw-r--r--usr/src/contrib/mDNSResponder/mDNSCore/anonymous.c623
-rw-r--r--usr/src/contrib/mDNSResponder/mDNSCore/anonymous.h31
-rw-r--r--usr/src/contrib/mDNSResponder/mDNSCore/dnsproxy.h9
-rw-r--r--usr/src/contrib/mDNSResponder/mDNSCore/dnssec.h158
-rwxr-xr-xusr/src/contrib/mDNSResponder/mDNSCore/mDNS.c4756
-rwxr-xr-xusr/src/contrib/mDNSResponder/mDNSCore/mDNSDebug.h303
-rwxr-xr-xusr/src/contrib/mDNSResponder/mDNSCore/mDNSEmbeddedAPI.h823
-rw-r--r--usr/src/contrib/mDNSResponder/mDNSCore/nsec.h34
-rwxr-xr-xusr/src/contrib/mDNSResponder/mDNSCore/uDNS.c1824
-rwxr-xr-xusr/src/contrib/mDNSResponder/mDNSCore/uDNS.h63
-rw-r--r--usr/src/contrib/mDNSResponder/mDNSPosix/PosixDaemon.c46
-rwxr-xr-xusr/src/contrib/mDNSResponder/mDNSPosix/mDNSPosix.c825
-rwxr-xr-xusr/src/contrib/mDNSResponder/mDNSPosix/mDNSPosix.h69
-rwxr-xr-xusr/src/contrib/mDNSResponder/mDNSPosix/mDNSUNP.h25
-rw-r--r--usr/src/contrib/mDNSResponder/mDNSPosix/posix_utilities.c28
-rw-r--r--usr/src/contrib/mDNSResponder/mDNSPosix/posix_utilities.h16
-rw-r--r--usr/src/contrib/mDNSResponder/mDNSShared/ClientRequests.c1068
-rw-r--r--usr/src/contrib/mDNSResponder/mDNSShared/ClientRequests.h165
-rw-r--r--usr/src/contrib/mDNSResponder/mDNSShared/GenLinkedList.c8
-rw-r--r--usr/src/contrib/mDNSResponder/mDNSShared/PlatformCommon.c572
-rw-r--r--usr/src/contrib/mDNSResponder/mDNSShared/PlatformCommon.h16
-rw-r--r--usr/src/contrib/mDNSResponder/mDNSShared/dns_sd.h288
-rw-r--r--usr/src/contrib/mDNSResponder/mDNSShared/dns_sd_internal.h23
-rw-r--r--usr/src/contrib/mDNSResponder/mDNSShared/dns_sd_private.h82
-rw-r--r--usr/src/contrib/mDNSResponder/mDNSShared/dnssd_clientstub.c482
-rw-r--r--usr/src/contrib/mDNSResponder/mDNSShared/dnssd_ipc.c28
-rw-r--r--usr/src/contrib/mDNSResponder/mDNSShared/dnssd_ipc.h13
-rw-r--r--usr/src/contrib/mDNSResponder/mDNSShared/mDNSDebug.c72
-rw-r--r--usr/src/contrib/mDNSResponder/mDNSShared/mDNSFeatures.h50
-rw-r--r--usr/src/contrib/mDNSResponder/mDNSShared/uds_daemon.c4300
-rw-r--r--usr/src/contrib/mDNSResponder/mDNSShared/uds_daemon.h73
-rw-r--r--usr/src/lib/brand/lx/lx_init/lxinit.c221
-rw-r--r--usr/src/lib/libc/Makefile.targ2
-rw-r--r--usr/src/lib/libc/inc/libc.h5
-rw-r--r--usr/src/lib/libc/sparc/Makefile.com4
-rw-r--r--usr/src/lib/libc/sparc/fp/_D_cplx_mul.c4
-rw-r--r--usr/src/lib/libc/sparc/fp/_F_cplx_mul.c4
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_cplx_div.c4
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_cplx_div_ix.c4
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_cplx_div_rx.c4
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_cplx_lr_div.c4
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_cplx_lr_div_ix.c4
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_cplx_lr_div_rx.c4
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_cplx_lr_mul.c4
-rw-r--r--usr/src/lib/libc/sparc/fp/_Q_cplx_mul.c4
-rw-r--r--usr/src/lib/libc/sparc/gen/getctxt.c9
-rw-r--r--usr/src/lib/libc/sparcv9/Makefile.com4
-rw-r--r--usr/src/lib/libc/sparcv9/gen/getctxt.c9
-rw-r--r--usr/src/lib/libdns_sd/Makefile.com2
-rw-r--r--usr/src/lib/libfru/libfruraw/fruraw.c11
-rw-r--r--usr/src/lib/libfru/libfruraw/raw_access.c2
-rw-r--r--usr/src/lib/libsldap/common/ns_confmgr.c28
-rw-r--r--usr/src/lib/libsldap/common/ns_reads.c14
-rw-r--r--usr/src/lib/nsswitch/ldap/common/getexecattr.c32
-rw-r--r--usr/src/lib/sun_sas/common/Sun_sasFreeLibrary.c1
-rw-r--r--usr/src/lib/sun_sas/common/Sun_sasLoadLibrary.c44
-rw-r--r--usr/src/lib/sun_sas/common/devtree_hba_disco.c2
-rw-r--r--usr/src/lib/sun_sas/common/sun_sas.h12
-rw-r--r--usr/src/man/man1m/nvmeadm.1m75
-rw-r--r--usr/src/pkg/manifests/diagnostic-pci.mf1
-rw-r--r--usr/src/pkg/manifests/system-test-utiltest.mf17
-rw-r--r--usr/src/test/util-tests/runfiles/default.run1
-rw-r--r--usr/src/test/util-tests/tests/Makefile2
-rw-r--r--usr/src/test/util-tests/tests/pcieadm/Makefile59
-rw-r--r--usr/src/test/util-tests/tests/pcieadm/bridge-efilt-p.out2
-rw-r--r--usr/src/test/util-tests/tests/pcieadm/bridge-efilt.out10
-rw-r--r--usr/src/test/util-tests/tests/pcieadm/bridge-ht-p.out1
-rw-r--r--usr/src/test/util-tests/tests/pcieadm/bridge-ht.msi-p.out1
-rw-r--r--usr/src/test/util-tests/tests/pcieadm/bridge-ht.msi.command-p.out1
-rw-r--r--usr/src/test/util-tests/tests/pcieadm/bridge-ht.out4
-rw-r--r--usr/src/test/util-tests/tests/pcieadm/bridge.pcibin0 -> 4096 bytes
-rw-r--r--usr/src/test/util-tests/tests/pcieadm/header0-basic-L.out3
-rw-r--r--usr/src/test/util-tests/tests/pcieadm/header0-basic-LH.out2
-rw-r--r--usr/src/test/util-tests/tests/pcieadm/header0-basic-n.out3
-rw-r--r--usr/src/test/util-tests/tests/pcieadm/header0-basic.out3
-rw-r--r--usr/src/test/util-tests/tests/pcieadm/header0-parse.out2
-rw-r--r--usr/src/test/util-tests/tests/pcieadm/igb-ltr-p.out1
-rw-r--r--usr/src/test/util-tests/tests/pcieadm/igb-ltr.out11
-rw-r--r--usr/src/test/util-tests/tests/pcieadm/igb.pcibin0 -> 4096 bytes
-rw-r--r--usr/src/test/util-tests/tests/pcieadm/pcieadmtest.ksh160
-rw-r--r--usr/src/tools/Makefile.tools3
-rw-r--r--usr/src/ucblib/libucb/sparc/sys/signal.c18
-rw-r--r--usr/src/uts/common/brand/lx/procfs/lx_proc.h1
-rw-r--r--usr/src/uts/common/brand/lx/procfs/lx_prvnops.c74
-rw-r--r--usr/src/uts/common/brand/lx/sys/lx_brand.h6
-rw-r--r--usr/src/uts/common/io/mlxcx/mlxcx.c29
-rw-r--r--usr/src/uts/common/io/mlxcx/mlxcx.h3
-rw-r--r--usr/src/uts/common/io/mlxcx/mlxcx_gld.c6
-rw-r--r--usr/src/uts/common/io/mlxcx/mlxcx_intr.c60
-rw-r--r--usr/src/uts/common/io/nvme/nvme.c16
-rw-r--r--usr/src/uts/common/io/pciex/pcie.c34
-rw-r--r--usr/src/uts/common/io/vioif/vioif.c258
-rw-r--r--usr/src/uts/common/io/vioif/vioif.h71
-rw-r--r--usr/src/uts/common/sys/pci.h5
-rw-r--r--usr/src/uts/common/sys/pcie.h9
-rw-r--r--usr/src/uts/i86pc/io/vmm/vmm.c10
-rw-r--r--usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c8
126 files changed, 18423 insertions, 8998 deletions
diff --git a/usr/src/boot/Makefile.version b/usr/src/boot/Makefile.version
index 656a8a3d08..88ac6f56a0 100644
--- a/usr/src/boot/Makefile.version
+++ b/usr/src/boot/Makefile.version
@@ -34,4 +34,4 @@ LOADER_VERSION = 1.1
# Use date like formatting here, YYYY.MM.DD.XX, without leading zeroes.
# The version is processed from left to right, the version number can only
# be increased.
-BOOT_VERSION = $(LOADER_VERSION)-2021.03.16.1
+BOOT_VERSION = $(LOADER_VERSION)-2021.04.03.1
diff --git a/usr/src/boot/lib/libstand/zfs/zfsimpl.c b/usr/src/boot/lib/libstand/zfs/zfsimpl.c
index 9ceb9b9794..e83a8a3983 100644
--- a/usr/src/boot/lib/libstand/zfs/zfsimpl.c
+++ b/usr/src/boot/lib/libstand/zfs/zfsimpl.c
@@ -175,10 +175,21 @@ nvlist_check_features_for_read(nvlist_t *nvl)
nv_string_t *nvp_name;
int rc;
+ /*
+ * We may have all features disabled.
+ */
rc = nvlist_find(nvl, ZPOOL_CONFIG_FEATURES_FOR_READ,
DATA_TYPE_NVLIST, NULL, &features, NULL);
- if (rc != 0)
- return (rc);
+ switch (rc) {
+ case 0:
+ break; /* Continue with checks */
+
+ case ENOENT:
+ return (0); /* All features are disabled */
+
+ default:
+ return (rc); /* Error while reading nvlist */
+ }
data = (nvs_data_t *)features->nv_data;
nvp = &data->nvl_pair; /* first pair in nvlist */
diff --git a/usr/src/cmd/Makefile b/usr/src/cmd/Makefile
index bd426edbb5..a4bacee105 100644
--- a/usr/src/cmd/Makefile
+++ b/usr/src/cmd/Makefile
@@ -306,6 +306,7 @@ COMMON_SUBDIRS= \
pbind \
pcidb \
pcidr \
+ pcieadm \
pcieb \
pcitool \
pfexec \
diff --git a/usr/src/cmd/cmd-inet/usr.bin/dns-sd/Makefile b/usr/src/cmd/cmd-inet/usr.bin/dns-sd/Makefile
index 8afabd17fe..23f5b3ba20 100644
--- a/usr/src/cmd/cmd-inet/usr.bin/dns-sd/Makefile
+++ b/usr/src/cmd/cmd-inet/usr.bin/dns-sd/Makefile
@@ -25,7 +25,7 @@ SRCS= ClientCommon.c dns-sd.c
SRCDIR= $(SRC)/contrib/mDNSResponder
CFLAGS += $(CSTD_GNU99)
CPPFLAGS += -I$(SRCDIR)/mDNSShared
-CPPFLAGS += -DmDNSResponderVersion=878.1.1
+CPPFLAGS += -DmDNSResponderVersion=1310.80.1
CPPFLAGS += -DMDNS_VERSIONSTR_NODTS
LDLIBS += -lsocket -ldns_sd
diff --git a/usr/src/cmd/cmd-inet/usr.bin/rdist/server.c b/usr/src/cmd/cmd-inet/usr.bin/rdist/server.c
index dd319ed40a..70002fb628 100644
--- a/usr/src/cmd/cmd-inet/usr.bin/rdist/server.c
+++ b/usr/src/cmd/cmd-inet/usr.bin/rdist/server.c
@@ -24,6 +24,7 @@
#include <limits.h>
#include <ctype.h>
#include <krb5defs.h>
+#include <stdarg.h>
/*
* If we want to write *to* the client rdist program, *from* the server
@@ -33,15 +34,15 @@
*/
int wrem = 1;
-#define ack() (void) write(wrem, "\0\n", 2)
-#define err() (void) write(wrem, "\1\n", 2)
+#define ack() (void) write(wrem, "\0\n", 2)
+#define err() (void) write(wrem, "\1\n", 2)
/*
* Set when a desread() is reqd. in response()
*/
struct linkbuf *ihead; /* list of files with more than one link */
-char buf[RDIST_BUFSIZ]; /* general purpose buffer */
+extern char buf[RDIST_BUFSIZ]; /* general purpose buffer */
char source[RDIST_BUFSIZ]; /* base source directory name */
char destination[RDIST_BUFSIZ]; /* base destination directory name */
char target[RDIST_BUFSIZ]; /* target/source directory name */
@@ -53,15 +54,15 @@ int oumask; /* old umask for creating files */
extern FILE *lfp; /* log file for mailing changes */
-void cleanup();
-struct linkbuf *savelink();
-char *strsub();
+void cleanup(int);
+struct linkbuf *savelink(struct stat *, int);
+char *strsub(char *, char *, char *);
-static void comment(char *s);
-static void note();
+static void comment(char *);
+static void note(char *, ...);
static void hardlink(char *cmd);
-void error();
-void log();
+void error(char *, ...);
+void log(FILE *, char *, ...);
static void recursive_remove(struct stat *stp);
static void recvf(char *cmd, int type);
static void query(char *name);
@@ -78,10 +79,10 @@ static void clean(char *cp);
* Qname - Query if file exists. Return mtime & size if it does.
*/
void
-server()
+server(void)
{
char cmdbuf[RDIST_BUFSIZ];
- register char *cp;
+ char *cp;
signal(SIGHUP, cleanup);
signal(SIGINT, cleanup);
@@ -105,7 +106,7 @@ server()
}
do {
if (read(rem, cp, 1) != 1)
- cleanup();
+ cleanup(0);
} while (*cp++ != '\n' && cp < &cmdbuf[RDIST_BUFSIZ]);
*--cp = '\0';
cp = cmdbuf;
@@ -231,9 +232,7 @@ server()
* (i.e., more than one source is being copied to the same destination).
*/
void
-install(src, dest, destdir, opts)
- char *src, *dest;
- int destdir, opts;
+install(char *src, char *dest, int destdir, int opts)
{
char *rname;
char destcopy[RDIST_BUFSIZ];
@@ -245,10 +244,10 @@ install(src, dest, destdir, opts)
if (nflag || debug) {
printf("%s%s%s%s%s %s %s\n", opts & VERIFY ? "verify":"install",
- opts & WHOLE ? " -w" : "",
- opts & YOUNGER ? " -y" : "",
- opts & COMPARE ? " -b" : "",
- opts & REMOVE ? " -R" : "", src, dest);
+ opts & WHOLE ? " -w" : "",
+ opts & YOUNGER ? " -y" : "",
+ opts & COMPARE ? " -b" : "",
+ opts & REMOVE ? " -R" : "", src, dest);
if (nflag)
return;
}
@@ -311,11 +310,9 @@ install(src, dest, destdir, opts)
* rname is the name of the file on the remote host.
*/
void
-sendf(rname, opts)
- char *rname;
- int opts;
+sendf(char *rname, int opts)
{
- register struct subcmd *sc;
+ struct subcmd *sc;
struct stat stb;
int sizerr, f, u, len;
off_t i;
@@ -348,14 +345,14 @@ sendf(rname, opts)
if (pw == NULL || pw->pw_uid != stb.st_uid)
if ((pw = getpwuid(stb.st_uid)) == NULL) {
log(lfp, "%s: no password entry for uid %d \n",
- target, stb.st_uid);
+ target, stb.st_uid);
pw = NULL;
sprintf(user, ":%d", stb.st_uid);
}
if (gr == NULL || gr->gr_gid != stb.st_gid)
if ((gr = getgrgid(stb.st_gid)) == NULL) {
log(lfp, "%s: no name for group %d\n",
- target, stb.st_gid);
+ target, stb.st_gid);
gr = NULL;
sprintf(group, ":%d", stb.st_gid);
}
@@ -401,7 +398,7 @@ sendf(rname, opts)
if ((int)(len + 1 + strlen(dp->d_name)) >=
(int)(RDIST_BUFSIZ - 1)) {
error("%.*s/%s: Name too long\n", len, target,
- dp->d_name);
+ dp->d_name);
continue;
}
tp = otp;
@@ -505,8 +502,8 @@ sendf(rname, opts)
return;
}
(void) snprintf(buf, sizeof (buf), "R%o %o %ld %ld %s %s %s\n", opts,
- stb.st_mode & 07777, stb.st_size, stb.st_mtime,
- protoname(), protogroup(), rname);
+ stb.st_mode & 07777, stb.st_size, stb.st_mtime,
+ protoname(), protogroup(), rname);
if (debug)
printf("buf = %s", buf);
(void) deswrite(rem, buf, strlen(buf), 0);
@@ -557,9 +554,7 @@ dospecial:
}
struct linkbuf *
-savelink(stp, opts)
- struct stat *stp;
- int opts;
+savelink(struct stat *stp, int opts)
{
struct linkbuf *lp;
@@ -600,18 +595,15 @@ savelink(stp, opts)
* and 3 if comparing binaries to determine if out of date.
*/
int
-update(rname, opts, stp)
- char *rname;
- int opts;
- struct stat *stp;
+update(char *rname, int opts, struct stat *stp)
{
- register char *cp, *s;
- register off_t size;
- register time_t mtime;
+ char *cp, *s;
+ off_t size;
+ time_t mtime;
if (debug)
printf("update(%s, %x%s, %x)\n", rname, opts,
- printb(opts, OBITS), stp);
+ printb(opts, OBITS), stp);
/*
* Check to see if the file exists on the remote machine.
@@ -731,8 +723,7 @@ more:
* ^Aerror message\n
*/
static void
-query(name)
- char *name;
+query(char *name)
{
struct stat stb;
@@ -774,11 +765,9 @@ query(name)
}
static void
-recvf(cmd, type)
- char *cmd;
- int type;
+recvf(char *cmd, int type)
{
- register char *cp;
+ char *cp;
int f, mode, opts, wrerr, olderrno;
off_t i, size;
time_t mtime;
@@ -843,7 +832,7 @@ recvf(cmd, type)
isdot = 0;
if (catname >= sizeof (stp) / sizeof (stp[0])) {
error("%s:%s: too many directory levels\n",
- host, target);
+ host, target);
return;
}
stp[catname] = tp;
@@ -915,7 +904,7 @@ recvf(cmd, type)
cp = buf;
for (i = 0; i < size; i += j) {
if ((j = read(rem, cp, size - i)) <= 0)
- cleanup();
+ cleanup(0);
cp += j;
}
*cp = '\0';
@@ -963,7 +952,7 @@ recvf(cmd, type)
if (j <= 0) {
(void) close(f);
(void) unlink(new);
- cleanup();
+ cleanup(0);
}
amt -= j;
cp += j;
@@ -1052,10 +1041,9 @@ badt:
* Creat a hard link to existing file.
*/
static void
-hardlink(cmd)
- char *cmd;
+hardlink(char *cmd)
{
- register char *cp;
+ char *cp;
struct stat stb;
char *oldname;
int opts, exists = 0;
@@ -1097,7 +1085,7 @@ hardlink(cmd)
}
if (chkparent(target) < 0) {
error("%s:%s: %s (no parent)\n",
- host, target, strerror(errno));
+ host, target, strerror(errno));
return;
}
if (opts & VERIFY) {
@@ -1116,14 +1104,14 @@ hardlink(cmd)
}
if (exists && (unlink(target) < 0)) {
error("%s:%s: %s (unlink)\n",
- host, target, strerror(errno));
+ host, target, strerror(errno));
return;
}
if (*oldname == '~')
oldname = exptilde(oldnamebuf, sizeof (oldnamebuf), oldname);
if (link(oldname, target) < 0) {
error("%s:can't link %s to %s\n",
- host, target, oldname);
+ host, target, oldname);
return;
}
ack();
@@ -1133,10 +1121,9 @@ hardlink(cmd)
* Check to see if parent directory exists and create one if not.
*/
int
-chkparent(name)
- char *name;
+chkparent(char *name)
{
- register char *cp;
+ char *cp;
struct stat stb;
cp = rindex(name, '/');
@@ -1161,11 +1148,9 @@ chkparent(name)
* Change owner, group and mode of file.
*/
int
-chog(file, owner, group, mode)
- char *file, *owner, *group;
- int mode;
+chog(char *file, char *owner, char *group, int mode)
{
- register int i;
+ int i;
uid_t uid, gid;
extern char user[];
@@ -1230,10 +1215,9 @@ ok:
* machine and remove them.
*/
static void
-rmchk(opts)
- int opts;
+rmchk(int opts)
{
- register char *cp, *s;
+ char *cp, *s;
struct stat stb;
if (debug)
@@ -1312,11 +1296,10 @@ rmchk(opts)
* for extraneous files and remove them.
*/
static void
-clean(cp)
- register char *cp;
+clean(char *cp)
{
DIR *d;
- register struct dirent *dp;
+ struct dirent *dp;
struct stat stb;
char *otp;
int len, opts;
@@ -1343,7 +1326,7 @@ clean(cp)
if ((int)(len + 1 + strlen(dp->d_name)) >=
(int)(RDIST_BUFSIZ - 1)) {
error("%s:%s/%s: Name too long\n",
- host, target, dp->d_name);
+ host, target, dp->d_name);
continue;
}
tp = otp;
@@ -1361,7 +1344,7 @@ clean(cp)
cp = buf;
do {
if (read(rem, cp, 1) != 1)
- cleanup();
+ cleanup(0);
} while (*cp++ != '\n' && cp < &buf[RDIST_BUFSIZ]);
*--cp = '\0';
cp = buf;
@@ -1384,12 +1367,11 @@ clean(cp)
* or an error message.
*/
static void
-recursive_remove(stp)
- struct stat *stp;
+recursive_remove(struct stat *stp)
{
DIR *d;
struct dirent *dp;
- register char *cp;
+ char *cp;
struct stat stb;
char *otp;
int len;
@@ -1421,7 +1403,7 @@ recursive_remove(stp)
if ((int)(len + 1 + strlen(dp->d_name)) >=
(int)(RDIST_BUFSIZ - 1)) {
error("%s:%s/%s: Name too long\n",
- host, target, dp->d_name);
+ host, target, dp->d_name);
continue;
}
tp = otp;
@@ -1452,11 +1434,10 @@ removed:
* Execute a shell command to handle special cases.
*/
static void
-dospecial(cmd)
- char *cmd;
+dospecial(char *cmd)
{
int fd[2], status, pid, i;
- register char *cp, *s;
+ char *cp, *s;
char sbuf[RDIST_BUFSIZ];
if (pipe(fd) < 0) {
@@ -1516,81 +1497,92 @@ dospecial(cmd)
ack();
}
-/*VARARGS2*/
void
-log(fp, fmt, a1, a2, a3)
- FILE *fp;
- char *fmt;
- int a1, a2, a3;
+log(FILE *fp, char *fmt, ...)
{
+ va_list ap;
+
/* Print changes locally if not quiet mode */
- if (!qflag)
- printf(fmt, a1, a2, a3);
+ if (!qflag) {
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+ }
/* Save changes (for mailing) if really updating files */
+ va_start(ap, fmt);
if (!(options & VERIFY) && fp != NULL)
- fprintf(fp, fmt, a1, a2, a3);
+ vfprintf(fp, fmt, ap);
+ va_end(ap);
}
-/*VARARGS1*/
void
-error(fmt, a1, a2, a3)
- char *fmt;
- int a1, a2, a3;
+error(char *fmt, ...)
{
+ va_list ap;
static FILE *fp;
nerrs++;
if (!fp && !(fp = fdopen(rem, "w")))
return;
if (iamremote) {
+ va_start(ap, fmt);
(void) fprintf(fp, "%crdist: ", 0x01);
- (void) fprintf(fp, fmt, a1, a2, a3);
+ (void) vfprintf(fp, fmt, ap);
fflush(fp);
+ va_end(ap);
} else {
+ va_start(ap, fmt);
fflush(stdout);
(void) fprintf(stderr, "rdist: ");
- (void) fprintf(stderr, fmt, a1, a2, a3);
+ (void) vfprintf(stderr, fmt, ap);
fflush(stderr);
+ va_end(ap);
}
if (lfp != NULL) {
+ va_start(ap, fmt);
(void) fprintf(lfp, "rdist: ");
- (void) fprintf(lfp, fmt, a1, a2, a3);
+ (void) vfprintf(lfp, fmt, ap);
fflush(lfp);
+ va_end(ap);
}
}
-/*VARARGS1*/
void
-fatal(fmt, a1, a2, a3)
- char *fmt;
- int a1, a2, a3;
+fatal(char *fmt, ...)
{
+ va_list ap;
static FILE *fp;
nerrs++;
if (!fp && !(fp = fdopen(rem, "w")))
return;
if (iamremote) {
+ va_start(ap, fmt);
(void) fprintf(fp, "%crdist: ", 0x02);
- (void) fprintf(fp, fmt, a1, a2, a3);
+ (void) vfprintf(fp, fmt, ap);
fflush(fp);
+ va_end(ap);
} else {
+ va_start(ap, fmt);
fflush(stdout);
(void) fprintf(stderr, "rdist: ");
- (void) fprintf(stderr, fmt, a1, a2, a3);
+ (void) vfprintf(stderr, fmt, ap);
fflush(stderr);
+ va_end(ap);
}
if (lfp != NULL) {
+ va_start(ap, fmt);
(void) fprintf(lfp, "rdist: ");
- (void) fprintf(lfp, fmt, a1, a2, a3);
+ (void) vfprintf(lfp, fmt, ap);
fflush(lfp);
+ va_end(ap);
}
- cleanup();
+ cleanup(0);
}
int
-response()
+response(void)
{
char *cp, *s;
char resp[RDIST_BUFSIZ];
@@ -1648,25 +1640,26 @@ more:
* Remove temporary files and do any cleanup operations before exiting.
*/
void
-cleanup()
+cleanup(int arg __unused)
{
(void) unlink(Tmpfile);
exit(1);
}
static void
-note(fmt, a1, a2, a3)
-char *fmt;
-int a1, a2, a3;
+note(char *fmt, ...)
{
+ va_list ap;
static char buf[RDIST_BUFSIZ];
- (void) snprintf(buf, sizeof (buf) - 1, fmt, a1, a2, a3);
+
+ va_start(ap, fmt);
+ (void) vsnprintf(buf, sizeof (buf) - 1, fmt, ap);
comment(buf);
+ va_end(ap);
}
static void
-comment(s)
-char *s;
+comment(char *s)
{
char three = '\3';
char nl = '\n';
@@ -1686,11 +1679,9 @@ char *s;
* N.B.: uses buf[].
*/
void
-sendrem(fmt, a1, a2, a3)
-char *fmt;
-int a1, a2, a3;
+sendrem(char *fmt, int a1, int a2, int a3)
{
- register int len;
+ int len;
buf[0] = '\0';
len = snprintf(buf + 1, sizeof (buf) - 1, fmt, a1, a2, a3) + 2;
@@ -1708,11 +1699,10 @@ int a1, a2, a3;
* substring old.
*/
char *
-strsub(old, new, s)
- char *old, *new, *s;
+strsub(char *old, char *new, char *s)
{
static char pbuf[PATH_MAX];
- register char *p, *q, *r, *plim;
+ char *p, *q, *r, *plim;
/* prepend new to pbuf */
for (p = pbuf, q = new, plim = pbuf + sizeof (pbuf) - 1;
diff --git a/usr/src/cmd/cmd-inet/usr.lib/mdnsd/Makefile b/usr/src/cmd/cmd-inet/usr.lib/mdnsd/Makefile
index 80ab750e70..a8c1280cc3 100644
--- a/usr/src/cmd/cmd-inet/usr.lib/mdnsd/Makefile
+++ b/usr/src/cmd/cmd-inet/usr.lib/mdnsd/Makefile
@@ -32,7 +32,8 @@ SRCDIR= $(SRC)/contrib/mDNSResponder
OBJS= DNSCommon.o DNSDigest.o GenLinkedList.o \
PlatformCommon.o PosixDaemon.o \
mDNS.o mDNSDebug.o mDNSPosix.o mDNSUNP.o \
- uDNS.o uds_daemon.o CryptoAlg.o anonymous.o dnssd_ipc.o
+ uDNS.o uds_daemon.o dnssd_ipc.o posix_utilities.o \
+ ClientRequests.o
SRCS= $(OBJS:%.o=%.c)
MDNSFLAGS= -DNOT_HAVE_SA_LEN \
@@ -40,12 +41,14 @@ MDNSFLAGS= -DNOT_HAVE_SA_LEN \
-D_XPG4_2 -D__EXTENSIONS__ -DHAVE_BROKEN_RECVIF_NAME \
-DHAVE_IPV6=1 -Dasm=__asm -DMDNSD_NOROOT \
-DPID_FILE=\"\" -DMDNSD_USER=\"noaccess\" \
- -DmDNSResponderVersion=878.260.1
+ -DmDNSResponderVersion=1310.80.1
include ../../../Makefile.cmd
CERRWARN += -_gcc=-Wno-unused-variable
CERRWARN += -_gcc=-Wno-implicit-function-declaration
+CERRWARN += -_gcc7=-Wno-expansion-to-defined
+CERRWARN += -_gcc10=-Wno-expansion-to-defined
CERRWARN += $(CNOWARN_UNINIT)
# not linted
diff --git a/usr/src/cmd/nvmeadm/Makefile b/usr/src/cmd/nvmeadm/Makefile
index 984c25112f..bc554ec2b8 100644
--- a/usr/src/cmd/nvmeadm/Makefile
+++ b/usr/src/cmd/nvmeadm/Makefile
@@ -18,7 +18,7 @@
PROG= nvmeadm
-OBJS= nvmeadm.o nvmeadm_dev.o nvmeadm_print.o
+OBJS= nvmeadm.o nvmeadm_dev.o nvmeadm_ofmt.o nvmeadm_print.o
SRCS= $(OBJS:%.o=%.c)
include ../Makefile.cmd
@@ -27,7 +27,7 @@ include ../Makefile.ctf
.KEEP_STATE:
CFLAGS += $(CCVERBOSE) -I$(SRC)/uts/common/io/nvme
-LDLIBS += -ldevinfo
+LDLIBS += -ldevinfo -lofmt
CSTD= $(CSTD_GNU99)
#
diff --git a/usr/src/cmd/nvmeadm/nvmeadm.c b/usr/src/cmd/nvmeadm/nvmeadm.c
index a13f0555ce..e177e04d82 100644
--- a/usr/src/cmd/nvmeadm/nvmeadm.c
+++ b/usr/src/cmd/nvmeadm/nvmeadm.c
@@ -49,27 +49,6 @@
#include "nvmeadm.h"
-typedef struct nvme_process_arg nvme_process_arg_t;
-typedef struct nvme_feature nvme_feature_t;
-typedef struct nvmeadm_cmd nvmeadm_cmd_t;
-
-struct nvme_process_arg {
- int npa_argc;
- char **npa_argv;
- char *npa_name;
- char *npa_nsid;
- int npa_found;
- boolean_t npa_isns;
- const nvmeadm_cmd_t *npa_cmd;
- di_node_t npa_node;
- di_minor_t npa_minor;
- char *npa_path;
- char *npa_dsk;
- nvme_identify_ctrl_t *npa_idctl;
- nvme_identify_nsid_t *npa_idns;
- nvme_version_t *npa_version;
-};
-
struct nvme_feature {
char *f_name;
char *f_short;
@@ -87,11 +66,12 @@ struct nvme_feature {
struct nvmeadm_cmd {
char *c_name;
- char *c_desc;
- char *c_flagdesc;
+ const char *c_desc;
+ const char *c_flagdesc;
int (*c_func)(int, const nvme_process_arg_t *);
void (*c_usage)(const char *);
boolean_t c_multi;
+ void (*c_optparse)(nvme_process_arg_t *);
};
@@ -121,6 +101,8 @@ static int do_firmware_load(int, const nvme_process_arg_t *);
static int do_firmware_commit(int, const nvme_process_arg_t *);
static int do_firmware_activate(int, const nvme_process_arg_t *);
+static void optparse_list(nvme_process_arg_t *);
+
static void usage_list(const char *);
static void usage_identify(const char *);
static void usage_get_logpage(const char *);
@@ -140,8 +122,9 @@ static const nvmeadm_cmd_t nvmeadm_cmds[] = {
{
"list",
"list controllers and namespaces",
- NULL,
- do_list, usage_list, B_TRUE
+ " -p\t\tprint parsable output\n"
+ " -o field\tselect a field for parsable output\n",
+ do_list, usage_list, B_TRUE, optparse_list
},
{
"identify",
@@ -257,12 +240,12 @@ int
main(int argc, char **argv)
{
int c;
- extern int optind;
const nvmeadm_cmd_t *cmd;
di_node_t node;
nvme_process_arg_t npa = { 0 };
int help = 0;
char *tmp, *lasts = NULL;
+ char *ctrl = NULL;
while ((c = getopt(argc, argv, "dhv")) != -1) {
switch (c) {
@@ -309,25 +292,42 @@ main(int argc, char **argv)
optind++;
/*
- * All commands but "list" require a ctl/ns argument.
+ * Store the remaining arguments for use by the command. Give the
+ * command a chance to process the options across the board before going
+ * into each controller.
*/
- if ((optind == argc || (strncmp(argv[optind], "nvme", 4) != 0)) &&
+ npa.npa_argc = argc - optind;
+ npa.npa_argv = &argv[optind];
+
+ if (cmd->c_optparse != NULL) {
+ cmd->c_optparse(&npa);
+ }
+
+ /*
+ * All commands but "list" require a ctl/ns argument. However, this
+ * should not be passed through to the command in its subsequent
+ * arguments.
+ */
+ if ((npa.npa_argc == 0 || (strncmp(npa.npa_argv[0], "nvme", 4) != 0)) &&
cmd->c_func != do_list) {
warnx("missing controller/namespace name");
usage(cmd);
exit(-1);
}
-
- /* Store the remaining arguments for use by the command. */
- npa.npa_argc = argc - optind - 1;
- npa.npa_argv = &argv[optind + 1];
+ if (npa.npa_argc > 0) {
+ ctrl = npa.npa_argv[0];
+ npa.npa_argv++;
+ npa.npa_argc--;
+ } else {
+ ctrl = NULL;
+ }
/*
* Make sure we're not running commands on multiple controllers that
* aren't allowed to do that.
*/
- if (argv[optind] != NULL && strchr(argv[optind], ',') != NULL &&
+ if (ctrl != NULL && strchr(ctrl, ',') != NULL &&
cmd->c_multi == B_FALSE) {
warnx("%s not allowed on multiple controllers",
cmd->c_name);
@@ -338,7 +338,7 @@ main(int argc, char **argv)
/*
* Get controller/namespace arguments and run command.
*/
- npa.npa_name = strtok_r(argv[optind], ",", &lasts);
+ npa.npa_name = strtok_r(ctrl, ",", &lasts);
do {
if (npa.npa_name != NULL) {
tmp = strchr(npa.npa_name, '/');
@@ -373,6 +373,15 @@ main(int argc, char **argv)
}
static void
+nvme_oferr(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ verrx(-1, fmt, ap);
+}
+
+static void
usage(const nvmeadm_cmd_t *cmd)
{
(void) fprintf(stderr, "usage:\n");
@@ -394,9 +403,9 @@ usage(const nvmeadm_cmd_t *cmd)
cmd->c_name, cmd->c_desc);
}
(void) fprintf(stderr, "\nflags:\n"
- " -h print usage information\n"
- " -d print information useful for debugging %s\n"
- " -v print verbose information\n", getprogname());
+ " -h\t\tprint usage information\n"
+ " -d\t\tprint information useful for debugging %s\n"
+ " -v\t\tprint verbose information\n", getprogname());
if (cmd != NULL && cmd->c_flagdesc != NULL)
(void) fprintf(stderr, "%s\n", cmd->c_flagdesc);
}
@@ -554,13 +563,63 @@ nvme_walk(nvme_process_arg_t *npa, di_node_t node)
static void
usage_list(const char *c_name)
{
- (void) fprintf(stderr, "%s [<ctl>[/<ns>][,...]\n\n"
+ (void) fprintf(stderr, "%s "
+ "[-p -o field[,...]] [<ctl>[/<ns>][,...]\n\n"
" List NVMe controllers and their namespaces. If no "
"controllers and/or name-\n spaces are specified, all "
"controllers and namespaces in the system will be\n "
"listed.\n", c_name);
}
+static void
+optparse_list(nvme_process_arg_t *npa)
+{
+ int c;
+ uint_t oflags = 0;
+ boolean_t parse = B_FALSE;
+ const char *fields = NULL;
+
+ optind = 0;
+ while ((c = getopt(npa->npa_argc, npa->npa_argv, ":o:p")) != -1) {
+ switch (c) {
+ case 'o':
+ fields = optarg;
+ break;
+ case 'p':
+ parse = B_TRUE;
+ oflags |= OFMT_PARSABLE;
+ break;
+ case '?':
+ errx(-1, "unknown list option: -%c", optopt);
+ break;
+ case ':':
+ errx(-1, "option -%c requires an argument", optopt);
+ default:
+ break;
+ }
+ }
+
+ if (fields != NULL && !parse) {
+ errx(-1, "-o can only be used when in parsable mode (-p)");
+ }
+
+ if (parse && fields == NULL) {
+ errx(-1, "parsable mode (-p) requires one to specify output "
+ "fields with -o");
+ }
+
+ if (parse) {
+ ofmt_status_t oferr;
+
+ oferr = ofmt_open(fields, nvme_list_ofmt, oflags, 0,
+ &npa->npa_ofmt);
+ ofmt_check(oferr, B_TRUE, npa->npa_ofmt, nvme_oferr, warnx);
+ }
+
+ npa->npa_argc -= optind;
+ npa->npa_argv += optind;
+}
+
static int
do_list_nsid(int fd, const nvme_process_arg_t *npa)
{
@@ -575,10 +634,14 @@ do_list_nsid(int fd, const nvme_process_arg_t *npa)
if ((bshift < 9 || npa->npa_idns->id_nsize == 0) && verbose == 0)
return (0);
- (void) printf(" %s/%s (%s): ", npa->npa_name,
- di_minor_name(npa->npa_minor),
- npa->npa_dsk != NULL ? npa->npa_dsk : "unattached");
- nvme_print_nsid_summary(npa->npa_idns);
+ if (npa->npa_ofmt == NULL) {
+ (void) printf(" %s/%s (%s): ", npa->npa_name,
+ di_minor_name(npa->npa_minor),
+ npa->npa_dsk != NULL ? npa->npa_dsk : "unattached");
+ nvme_print_nsid_summary(npa->npa_idns);
+ } else {
+ ofmt_print(npa->npa_ofmt, (void *)npa);
+ }
return (0);
}
@@ -596,8 +659,10 @@ do_list(int fd, const nvme_process_arg_t *npa)
di_instance(npa->npa_node)) < 0)
err(-1, "do_list()");
- (void) printf("%s: ", name);
- nvme_print_ctrl_summary(npa->npa_idctl, npa->npa_version);
+ if (npa->npa_ofmt == NULL) {
+ (void) printf("%s: ", name);
+ nvme_print_ctrl_summary(npa->npa_idctl, npa->npa_version);
+ }
ns_npa.npa_name = name;
ns_npa.npa_isns = B_TRUE;
@@ -605,6 +670,8 @@ do_list(int fd, const nvme_process_arg_t *npa)
cmd = *(npa->npa_cmd);
cmd.c_func = do_list_nsid;
ns_npa.npa_cmd = &cmd;
+ ns_npa.npa_ofmt = npa->npa_ofmt;
+ ns_npa.npa_idctl = npa->npa_idctl;
nvme_walk(&ns_npa, npa->npa_node);
diff --git a/usr/src/cmd/nvmeadm/nvmeadm.h b/usr/src/cmd/nvmeadm/nvmeadm.h
index 0ccd299980..ff6a21c87f 100644
--- a/usr/src/cmd/nvmeadm/nvmeadm.h
+++ b/usr/src/cmd/nvmeadm/nvmeadm.h
@@ -22,6 +22,7 @@
#include <libdevinfo.h>
#include <sys/nvme.h>
#include <nvme_reg.h>
+#include <ofmt.h>
#ifdef __cplusplus
extern "C" {
@@ -30,10 +31,34 @@ extern "C" {
extern int verbose;
extern int debug;
+/* Common structures */
+typedef struct nvme_process_arg nvme_process_arg_t;
+typedef struct nvme_feature nvme_feature_t;
+typedef struct nvmeadm_cmd nvmeadm_cmd_t;
+
+struct nvme_process_arg {
+ int npa_argc;
+ char **npa_argv;
+ char *npa_name;
+ char *npa_nsid;
+ int npa_found;
+ boolean_t npa_isns;
+ const nvmeadm_cmd_t *npa_cmd;
+ di_node_t npa_node;
+ di_minor_t npa_minor;
+ char *npa_path;
+ char *npa_dsk;
+ nvme_identify_ctrl_t *npa_idctl;
+ nvme_identify_nsid_t *npa_idns;
+ nvme_version_t *npa_version;
+ ofmt_handle_t npa_ofmt;
+};
+
/* Version checking */
extern boolean_t nvme_version_check(nvme_version_t *, uint_t, uint_t);
/* printing functions */
+extern int nvme_strlen(const char *, int);
extern void nvme_print(int, const char *, int, const char *, ...);
extern void nvme_print_ctrl_summary(nvme_identify_ctrl_t *, nvme_version_t *);
extern void nvme_print_nsid_summary(nvme_identify_nsid_t *);
@@ -91,6 +116,11 @@ extern boolean_t nvme_attach(int);
extern boolean_t nvme_firmware_load(int, void *, size_t, offset_t);
extern boolean_t nvme_firmware_commit(int fd, int, int, uint16_t *, uint16_t *);
+/*
+ * ofmt related
+ */
+extern const ofmt_field_t nvme_list_ofmt[];
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/cmd/nvmeadm/nvmeadm_ofmt.c b/usr/src/cmd/nvmeadm/nvmeadm_ofmt.c
new file mode 100644
index 0000000000..825417eb76
--- /dev/null
+++ b/usr/src/cmd/nvmeadm/nvmeadm_ofmt.c
@@ -0,0 +1,132 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2021 Oxide Computer Company
+ */
+
+/*
+ * nvmeadm output formatting for ofmt based rendering
+ */
+
+#include <strings.h>
+
+#include "nvmeadm.h"
+
+typedef enum nvme_list_ofmt_field {
+ NVME_LIST_MODEL,
+ NVME_LIST_SERIAL,
+ NVME_LIST_FWREV,
+ NVME_LIST_VERSION,
+ NVME_LIST_SIZE,
+ NVME_LIST_CAPACITY,
+ NVME_LIST_USED,
+ NVME_LIST_INSTANCE,
+ NVME_LIST_NAMESPACE,
+ NVME_LIST_DISK
+} nvme_list_ofmt_field_t;
+
+static boolean_t
+nvme_list_ofmt_cb(ofmt_arg_t *ofmt_arg, char *buf, uint_t buflen)
+{
+ const nvme_process_arg_t *npa = ofmt_arg->ofmt_cbarg;
+ nvme_idns_lbaf_t *lbaf;
+ uint_t blksize;
+ uint64_t val;
+ int nvmelen;
+ size_t ret;
+
+ lbaf = &npa->npa_idns->id_lbaf[npa->npa_idns->id_flbas.lba_format];
+ blksize = 1 << lbaf->lbaf_lbads;
+
+ switch (ofmt_arg->ofmt_id) {
+ case NVME_LIST_MODEL:
+ nvmelen = nvme_strlen(npa->npa_idctl->id_model,
+ sizeof (npa->npa_idctl->id_model));
+ if (nvmelen <= 0 || nvmelen > buflen) {
+ return (B_FALSE);
+ }
+ (void) memcpy(buf, npa->npa_idctl->id_model, nvmelen);
+ buf[nvmelen] = '\0';
+ ret = nvmelen;
+ break;
+ case NVME_LIST_SERIAL:
+ nvmelen = nvme_strlen(npa->npa_idctl->id_serial,
+ sizeof (npa->npa_idctl->id_serial));
+ if (nvmelen <= 0 || nvmelen >= buflen) {
+ return (B_FALSE);
+ }
+ (void) memcpy(buf, npa->npa_idctl->id_serial, nvmelen);
+ buf[nvmelen] = '\0';
+ ret = nvmelen;
+ break;
+ case NVME_LIST_FWREV:
+ nvmelen = nvme_strlen(npa->npa_idctl->id_fwrev,
+ sizeof (npa->npa_idctl->id_fwrev));
+ if (nvmelen <= 0 || nvmelen >= buflen) {
+ return (B_FALSE);
+ }
+ (void) memcpy(buf, npa->npa_idctl->id_fwrev, nvmelen);
+ buf[nvmelen] = '\0';
+ ret = nvmelen;
+ break;
+ case NVME_LIST_VERSION:
+ ret = snprintf(buf, buflen, "%u.%u", npa->npa_version->v_major,
+ npa->npa_version->v_minor);
+ break;
+ case NVME_LIST_INSTANCE:
+ ret = strlcat(buf, npa->npa_name, buflen);
+ break;
+ case NVME_LIST_NAMESPACE:
+ ret = strlcat(buf, di_minor_name(npa->npa_minor), buflen);
+ break;
+ case NVME_LIST_DISK:
+ if (npa->npa_dsk != NULL) {
+ ret = strlcat(buf, npa->npa_dsk, buflen);
+ } else {
+ ret = strlcat(buf, "--", buflen);
+ }
+ break;
+ case NVME_LIST_SIZE:
+ val = npa->npa_idns->id_nsize * blksize;
+ ret = snprintf(buf, buflen, "%" PRIu64, val);
+ break;
+ case NVME_LIST_CAPACITY:
+ val = npa->npa_idns->id_ncap * blksize;
+ ret = snprintf(buf, buflen, "%" PRIu64, val);
+ break;
+ case NVME_LIST_USED:
+ val = npa->npa_idns->id_nuse * blksize;
+ ret = snprintf(buf, buflen, "%" PRIu64, val);
+ break;
+ default:
+ abort();
+ }
+
+ if (ret >= buflen) {
+ return (B_FALSE);
+ }
+ return (B_TRUE);
+}
+
+const ofmt_field_t nvme_list_ofmt[] = {
+ { "MODEL", 30, NVME_LIST_MODEL, nvme_list_ofmt_cb },
+ { "SERIAL", 30, NVME_LIST_SERIAL, nvme_list_ofmt_cb },
+ { "FWREV", 10, NVME_LIST_FWREV, nvme_list_ofmt_cb },
+ { "VERSION", 10, NVME_LIST_VERSION, nvme_list_ofmt_cb },
+ { "SIZE", 15, NVME_LIST_SIZE, nvme_list_ofmt_cb },
+ { "CAPACITY", 15, NVME_LIST_CAPACITY, nvme_list_ofmt_cb },
+ { "USED", 15, NVME_LIST_USED, nvme_list_ofmt_cb },
+ { "INSTANCE", 10, NVME_LIST_INSTANCE, nvme_list_ofmt_cb },
+ { "NAMESPACE", 10, NVME_LIST_NAMESPACE, nvme_list_ofmt_cb },
+ { "DISK", 15, NVME_LIST_DISK, nvme_list_ofmt_cb },
+ { NULL, 0, 0, NULL }
+};
diff --git a/usr/src/cmd/nvmeadm/nvmeadm_print.c b/usr/src/cmd/nvmeadm/nvmeadm_print.c
index 34006bc253..9190131566 100644
--- a/usr/src/cmd/nvmeadm/nvmeadm_print.c
+++ b/usr/src/cmd/nvmeadm/nvmeadm_print.c
@@ -31,8 +31,6 @@
#include "nvmeadm.h"
-static int nvme_strlen(const char *, int);
-
static void nvme_print_str(int, const char *, int, const char *, int);
static void nvme_print_double(int, const char *, double, int, const char *);
static void nvme_print_int64(int, const char *, uint64_t, const char *,
@@ -244,7 +242,7 @@ nvme_print(int indent, const char *name, int index, const char *fmt, ...)
/*
* nvme_strlen -- return length of string without trailing whitespace
*/
-static int
+int
nvme_strlen(const char *str, int len)
{
if (len < 0)
@@ -483,7 +481,7 @@ nvme_print_version(int indent, const char *name, uint32_t value)
void
nvme_print_ctrl_summary(nvme_identify_ctrl_t *idctl, nvme_version_t *version)
{
- (void) printf("model: %.*s, serial: %.*s, FW rev: %.*s, NVMe v%d.%d\n",
+ (void) printf("model: %.*s, serial: %.*s, FW rev: %.*s, NVMe v%u.%u\n",
nvme_strlen(idctl->id_model, sizeof (idctl->id_model)),
idctl->id_model,
nvme_strlen(idctl->id_serial, sizeof (idctl->id_serial)),
diff --git a/usr/src/cmd/pcieadm/Makefile b/usr/src/cmd/pcieadm/Makefile
new file mode 100644
index 0000000000..c8b17c2a3a
--- /dev/null
+++ b/usr/src/cmd/pcieadm/Makefile
@@ -0,0 +1,45 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2021 Oxide Computer Company
+#
+
+PROG= pcieadm
+
+include ../Makefile.cmd
+include ../Makefile.cmd.64
+include ../Makefile.ctf
+
+CFLAGS += $(CCVERBOSE)
+CSTD = $(CSTD_GNU99)
+LDLIBS += -ldevinfo -lpcidb -lofmt
+OBJS = pcieadm.o pcieadm_cfgspace.o pcieadm_devs.o
+ROOTCMDDIR = $(ROOTLIB)/pci
+
+.KEEP_STATE:
+
+$(PROG): $(OBJS)
+ $(LINK.c) -o $@ $(OBJS) $(LDLIBS)
+ $(POST_PROCESS)
+
+%.o: %.c
+ $(COMPILE.c) $<
+ $(POST_PROCESS_O)
+
+all: $(PROG)
+
+install: all $(ROOTCMD)
+
+clean:
+ $(RM) $(OBJS)
+
+include ../Makefile.targ
diff --git a/usr/src/cmd/pcieadm/pcieadm.c b/usr/src/cmd/pcieadm/pcieadm.c
new file mode 100644
index 0000000000..edcad6e4d8
--- /dev/null
+++ b/usr/src/cmd/pcieadm/pcieadm.c
@@ -0,0 +1,624 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2021 Oxide Computer Company
+ */
+
+/*
+ * PCIe shenanigans
+ *
+ * Currently this implements several different views at seeing into PCIe devices
+ * and is designed to (hopefully) replace pcitool and be a vector for new system
+ * functionality such as dealing with multicast filtering, ACS, etc.
+ *
+ * While most subcommands have their own implementations, there are a couple of
+ * things that are worth bearing in mind:
+ *
+ * 1) Where possible, prefer the use of libofmt. In particular, having good,
+ * parsable output is important. New subcommands should strive to meet that.
+ *
+ * 2) Because we're often processing binary data (and it's good hygiene),
+ * subcommands should make sure to drop privileges as early as they can by
+ * calling pcieadm_init_privs(). More on privileges below.
+ *
+ * Privilege Management
+ * --------------------
+ *
+ * In an attempt to minimize privilege exposure, but to allow subcommands
+ * flexibility when required (e.g. show-cfgspace needs full privs to read from
+ * the kernel), we have two privilege sets that we maintain. One which is the
+ * minimial privs, which basically is a set that has stripped everything. This
+ * is 'pia_priv_min'. The second is one that allows a subcommand to add in
+ * privileges that it requires which will be left in the permitted set. These
+ * are in 'pia_priv_eff'. It's important to know that this set is always
+ * intersected with what the user actually has, so this is not meant to be a way
+ * for a caller to get more privileges than they already have.
+ *
+ * A subcommand is expected to call pcieadm_init_privs() once they have
+ * processed enough arguments that they can set an upper bound on privileges.
+ * It's worth noting that a subcommand will be executed in an already minimial
+ * environment; however, we will have already set up a libdevinfo handle for
+ * them, which should make the need to do much more not so bad.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <err.h>
+#include <libdevinfo.h>
+#include <strings.h>
+#include <sys/stat.h>
+#include <sys/pci_tools.h>
+#include <sys/pci.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/debug.h>
+#include <upanic.h>
+#include <libgen.h>
+
+#include "pcieadm.h"
+
+pcieadm_t pcieadm;
+const char *pcieadm_progname;
+
+void
+pcieadm_init_privs(pcieadm_t *pcip)
+{
+ static const char *msg = "attempted to re-initialize privileges";
+ if (pcip->pia_priv_init == NULL) {
+ upanic(msg, strlen(msg));
+ }
+
+ priv_intersect(pcip->pia_priv_init, pcip->pia_priv_eff);
+
+ if (setppriv(PRIV_SET, PRIV_PERMITTED, pcieadm.pia_priv_eff) != 0) {
+ err(EXIT_FAILURE, "failed to reduce privileges");
+ }
+
+ if (setppriv(PRIV_SET, PRIV_LIMIT, pcieadm.pia_priv_eff) != 0) {
+ err(EXIT_FAILURE, "failed to reduce privileges");
+ }
+
+ priv_freeset(pcip->pia_priv_init);
+ pcip->pia_priv_init = NULL;
+}
+
+void
+pcieadm_indent(void)
+{
+ pcieadm.pia_indent += 2;
+}
+
+void
+pcieadm_deindent(void)
+{
+ VERIFY3U(pcieadm.pia_indent, >, 0);
+ pcieadm.pia_indent -= 2;
+}
+
+void
+pcieadm_print(const char *fmt, ...)
+{
+ va_list ap;
+
+ if (pcieadm.pia_indent > 0) {
+ (void) printf("%*s", pcieadm.pia_indent, "");
+ }
+
+ va_start(ap, fmt);
+ (void) vprintf(fmt, ap);
+ va_end(ap);
+}
+
+void
+pcieadm_ofmt_errx(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ verrx(EXIT_FAILURE, fmt, ap);
+}
+
+boolean_t
+pcieadm_di_node_is_pci(di_node_t node)
+{
+ const char *name;
+
+ name = di_node_name(node);
+ return (strncmp("pci", name, 3) == 0);
+}
+
+static int
+pcieadm_di_walk_cb(di_node_t node, void *arg)
+{
+ pcieadm_di_walk_t *walk = arg;
+
+ if (!pcieadm_di_node_is_pci(node)) {
+ return (DI_WALK_CONTINUE);
+ }
+
+ /*
+ * We create synthetic nodes for the root of PCIe tree basically
+ * functions as all the resources available for one or more bridges.
+ * When we encounter that top-level node skip it.
+ */
+ if (strcmp("pci", di_node_name(node)) == 0) {
+ return (DI_WALK_CONTINUE);
+ }
+
+ return (walk->pdw_func(node, walk->pdw_arg));
+}
+
+void
+pcieadm_di_walk(pcieadm_t *pcip, pcieadm_di_walk_t *arg)
+{
+ (void) di_walk_node(pcip->pia_root, DI_WALK_CLDFIRST, arg,
+ pcieadm_di_walk_cb);
+}
+
+/*
+ * Attempt to find the nexus that corresponds to this device. To do this, we
+ * walk up and walk the minors until we find a "reg" minor.
+ */
+void
+pcieadm_find_nexus(pcieadm_t *pia)
+{
+ di_node_t cur;
+
+ for (cur = di_parent_node(pia->pia_devi); cur != DI_NODE_NIL;
+ cur = di_parent_node(cur)) {
+ di_minor_t minor = DI_MINOR_NIL;
+
+ while ((minor = di_minor_next(cur, minor)) != DI_MINOR_NIL) {
+ if (di_minor_spectype(minor) == S_IFCHR &&
+ strcmp(di_minor_name(minor), "reg") == 0) {
+ pia->pia_nexus = cur;
+ return;
+ }
+ }
+ }
+}
+
+static int
+pcieadm_find_dip_cb(di_node_t node, void *arg)
+{
+ char *path = NULL, *driver;
+ char dinst[128], bdf[128], altbdf[128];
+ int inst, nprop, *regs;
+ pcieadm_t *pia = arg;
+
+ path = di_devfs_path(node);
+ if (path == NULL) {
+ err(EXIT_FAILURE, "failed to construct devfs path for node: "
+ "%s (%s)", di_node_name(node));
+ }
+
+ driver = di_driver_name(node);
+ inst = di_instance(node);
+ if (driver != NULL && inst != -1) {
+ (void) snprintf(dinst, sizeof (dinst), "%s%d", driver, inst);
+ }
+
+ nprop = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", &regs);
+ if (nprop <= 0) {
+ errx(EXIT_FAILURE, "failed to lookup regs array for %s",
+ path);
+ }
+ (void) snprintf(bdf, sizeof (bdf), "%x/%x/%x", PCI_REG_BUS_G(regs[0]),
+ PCI_REG_DEV_G(regs[0]), PCI_REG_FUNC_G(regs[0]));
+ (void) snprintf(bdf, sizeof (bdf), "%02x/%02x/%02x",
+ PCI_REG_BUS_G(regs[0]), PCI_REG_DEV_G(regs[0]),
+ PCI_REG_FUNC_G(regs[0]));
+
+ if (strcmp(pia->pia_devstr, path) == 0 ||
+ strcmp(pia->pia_devstr, bdf) == 0 ||
+ strcmp(pia->pia_devstr, altbdf) == 0 ||
+ (driver != NULL && inst != -1 &&
+ strcmp(pia->pia_devstr, dinst) == 0)) {
+ if (pia->pia_devi != DI_NODE_NIL) {
+ errx(EXIT_FAILURE, "device name matched two device "
+ "nodes: %s and %s", di_node_name(pia->pia_devi),
+ di_node_name(node));
+ }
+
+ pia->pia_devi = node;
+ }
+
+ if (path != NULL) {
+ di_devfs_path_free(path);
+ }
+
+ return (DI_WALK_CONTINUE);
+}
+
+void
+pcieadm_find_dip(pcieadm_t *pcip, const char *device)
+{
+ pcieadm_di_walk_t walk;
+
+ /*
+ * If someone specifies /devices, just skip over it.
+ */
+ pcip->pia_devstr = device;
+ if (strncmp("/devices", device, strlen("/devices")) == 0) {
+ pcip->pia_devstr += strlen("/devices");
+ }
+
+ pcip->pia_devi = DI_NODE_NIL;
+ walk.pdw_arg = pcip;
+ walk.pdw_func = pcieadm_find_dip_cb;
+ pcieadm_di_walk(pcip, &walk);
+
+ if (pcip->pia_devi == DI_NODE_NIL) {
+ errx(EXIT_FAILURE, "failed to find device node %s", device);
+ }
+
+ pcip->pia_nexus = DI_NODE_NIL;
+ pcieadm_find_nexus(pcip);
+ if (pcip->pia_nexus == DI_NODE_NIL) {
+ errx(EXIT_FAILURE, "failed to find nexus for %s", device);
+ }
+}
+
+typedef struct pcieadm_cfgspace_file {
+ int pcfi_fd;
+} pcieadm_cfgspace_file_t;
+
+static boolean_t
+pcieadm_read_cfgspace_file(uint32_t off, uint8_t len, void *buf, void *arg)
+{
+ uint32_t bufoff = 0;
+ pcieadm_cfgspace_file_t *pcfi = arg;
+
+ while (len > 0) {
+ ssize_t ret = pread(pcfi->pcfi_fd, buf + bufoff, len, off);
+ if (ret < 0) {
+ err(EXIT_FAILURE, "failed to read %u bytes at %"
+ PRIu32, len, off);
+ } else if (ret == 0) {
+ warnx("hit unexpected EOF reading cfgspace from file "
+ "at offest %" PRIu32 ", still wanted to read %u "
+ "bytes", off, len);
+ return (B_FALSE);
+ } else {
+ len -= ret;
+ off += ret;
+ bufoff += ret;
+ }
+
+ }
+
+ return (B_TRUE);
+}
+
+void
+pcieadm_init_cfgspace_file(pcieadm_t *pcip, const char *path,
+ pcieadm_cfgspace_f *funcp, void **arg)
+{
+ int fd;
+ struct stat st;
+ pcieadm_cfgspace_file_t *pcfi;
+
+ if (setppriv(PRIV_SET, PRIV_EFFECTIVE, pcip->pia_priv_eff) != 0) {
+ err(EXIT_FAILURE, "failed to raise privileges");
+ }
+
+ if ((fd = open(path, O_RDONLY)) < 0) {
+ err(EXIT_FAILURE, "failed to open input file %s", path);
+ }
+
+ if (fstat(fd, &st) != 0) {
+ err(EXIT_FAILURE, "failed to get stat information for %s",
+ path);
+ }
+
+ if (setppriv(PRIV_SET, PRIV_EFFECTIVE, pcip->pia_priv_min) != 0) {
+ err(EXIT_FAILURE, "failed to reduce privileges");
+ }
+
+ if (S_ISDIR(st.st_mode)) {
+ errx(EXIT_FAILURE, "input file %s is a directory, unable "
+ "to read data", path);
+ }
+
+ if (S_ISLNK(st.st_mode)) {
+ errx(EXIT_FAILURE, "input file %s is a symbolic link, unable "
+ "to read data", path);
+ }
+
+ if (S_ISDOOR(st.st_mode)) {
+ errx(EXIT_FAILURE, "input file %s is a door, unable "
+ "to read data", path);
+ }
+
+ if (S_ISPORT(st.st_mode)) {
+ errx(EXIT_FAILURE, "input file %s is an event port, unable "
+ "to read data", path);
+ }
+
+ /*
+ * Assume if we were given a FIFO, character/block device, socket, or
+ * something else that it's probably fine.
+ */
+ pcfi = calloc(1, sizeof (*pcfi));
+ if (pcfi == NULL) {
+ err(EXIT_FAILURE, "failed to allocate memory for reading "
+ "cfgspace data from a file");
+ }
+
+ pcfi->pcfi_fd = fd;
+ *arg = pcfi;
+ *funcp = pcieadm_read_cfgspace_file;
+}
+
+void
+pcieadm_fini_cfgspace_file(void *arg)
+{
+ pcieadm_cfgspace_file_t *pcfi = arg;
+ VERIFY0(close(pcfi->pcfi_fd));
+ free(pcfi);
+}
+
+typedef struct pcieadm_cfgspace_kernel {
+ pcieadm_t *pck_pci;
+ int pck_fd;
+ uint8_t pck_bus;
+ uint8_t pck_dev;
+ uint8_t pck_func;
+} pcieadm_cfgspace_kernel_t;
+
+static boolean_t
+pcieadm_read_cfgspace_kernel(uint32_t off, uint8_t len, void *buf, void *arg)
+{
+ pcieadm_cfgspace_kernel_t *pck = arg;
+ pcieadm_t *pcip = pck->pck_pci;
+ pcitool_reg_t pci_reg;
+
+ bzero(&pci_reg, sizeof (pci_reg));
+ pci_reg.user_version = PCITOOL_VERSION;
+ pci_reg.bus_no = pck->pck_bus;
+ pci_reg.dev_no = pck->pck_dev;
+ pci_reg.func_no = pck->pck_func;
+ pci_reg.barnum = 0;
+ pci_reg.offset = off;
+ pci_reg.acc_attr = PCITOOL_ACC_ATTR_ENDN_LTL;
+
+ switch (len) {
+ case 1:
+ pci_reg.acc_attr += PCITOOL_ACC_ATTR_SIZE_1;
+ break;
+ case 2:
+ pci_reg.acc_attr += PCITOOL_ACC_ATTR_SIZE_2;
+ break;
+ case 4:
+ pci_reg.acc_attr += PCITOOL_ACC_ATTR_SIZE_4;
+ break;
+ case 8:
+ pci_reg.acc_attr += PCITOOL_ACC_ATTR_SIZE_8;
+ break;
+ default:
+ errx(EXIT_FAILURE, "asked to read invalid size from kernel: %u",
+ len);
+ }
+
+ if (setppriv(PRIV_SET, PRIV_EFFECTIVE, pcip->pia_priv_eff) != 0) {
+ err(EXIT_FAILURE, "failed to raise privileges");
+ }
+
+ if (ioctl(pck->pck_fd, PCITOOL_DEVICE_GET_REG, &pci_reg) != 0) {
+ err(EXIT_FAILURE, "failed to read device offset 0x%x", off);
+ }
+
+ if (setppriv(PRIV_SET, PRIV_EFFECTIVE, pcip->pia_priv_min) != 0) {
+ err(EXIT_FAILURE, "failed to reduce privileges");
+ }
+
+ switch (len) {
+ case 1:
+ *(uint8_t *)buf = (uint8_t)pci_reg.data;
+ break;
+ case 2:
+ *(uint16_t *)buf = (uint16_t)pci_reg.data;
+ break;
+ case 4:
+ *(uint32_t *)buf = (uint32_t)pci_reg.data;
+ break;
+ case 8:
+ *(uint64_t *)buf = (uint64_t)pci_reg.data;
+ break;
+ }
+
+ return (B_TRUE);
+}
+
+void
+pcieadm_init_cfgspace_kernel(pcieadm_t *pcip, pcieadm_cfgspace_f *funcp,
+ void **arg)
+{
+ char *nexus_base;
+ char nexus_reg[PATH_MAX];
+ int fd, nregs, *regs;
+ pcieadm_cfgspace_kernel_t *pck;
+
+ if ((nexus_base = di_devfs_path(pcip->pia_nexus)) == NULL) {
+ err(EXIT_FAILURE, "failed to get path to nexus node");
+ }
+
+ if (snprintf(nexus_reg, sizeof (nexus_reg), "/devices%s:reg",
+ nexus_base) >= sizeof (nexus_reg)) {
+ errx(EXIT_FAILURE, "failed to construct nexus path, path "
+ "overflow");
+ }
+ free(nexus_base);
+
+ if (setppriv(PRIV_SET, PRIV_EFFECTIVE, pcip->pia_priv_eff) != 0) {
+ err(EXIT_FAILURE, "failed to raise privileges");
+ }
+
+ if ((fd = open(nexus_reg, O_RDONLY)) < 0) {
+ err(EXIT_FAILURE, "failed to open %s", nexus_reg);
+ }
+
+ if (setppriv(PRIV_SET, PRIV_EFFECTIVE, pcip->pia_priv_min) != 0) {
+ err(EXIT_FAILURE, "failed to reduce privileges");
+ }
+
+ nregs = di_prop_lookup_ints(DDI_DEV_T_ANY, pcip->pia_devi, "reg",
+ &regs);
+ if (nregs <= 0) {
+ errx(EXIT_FAILURE, "failed to lookup regs array for %s",
+ pcip->pia_devstr);
+ }
+
+ pck = calloc(1, sizeof (pcieadm_cfgspace_kernel_t));
+ if (pck == NULL) {
+ err(EXIT_FAILURE, "failed to allocate memory for reading "
+ "kernel cfgspace data");
+ }
+
+ pck->pck_pci = pcip;
+ pck->pck_fd = fd;
+ pck->pck_bus = PCI_REG_BUS_G(regs[0]);
+ pck->pck_dev = PCI_REG_DEV_G(regs[0]);
+ pck->pck_func = PCI_REG_FUNC_G(regs[0]);
+
+ *funcp = pcieadm_read_cfgspace_kernel;
+ *arg = pck;
+}
+
+void
+pcieadm_fini_cfgspace_kernel(void *arg)
+{
+ pcieadm_cfgspace_kernel_t *pck = arg;
+
+ VERIFY0(close(pck->pck_fd));
+ free(pck);
+}
+
+static const pcieadm_cmdtab_t pcieadm_cmds[] = {
+ { "save-cfgspace", pcieadm_save_cfgspace, pcieadm_save_cfgspace_usage },
+ { "show-cfgspace", pcieadm_show_cfgspace, pcieadm_show_cfgspace_usage },
+ { "show-devs", pcieadm_show_devs, pcieadm_show_devs_usage },
+ { NULL }
+};
+
+static void
+pcieadm_usage(const char *format, ...)
+{
+ uint_t cmd;
+
+ if (format != NULL) {
+ va_list ap;
+
+ va_start(ap, format);
+ vwarnx(format, ap);
+ va_end(ap);
+ }
+
+ (void) fprintf(stderr, "usage: %s <subcommand> <args> ...\n\n",
+ pcieadm_progname);
+
+ for (cmd = 0; pcieadm_cmds[cmd].pct_name != NULL; cmd++) {
+ if (pcieadm_cmds[cmd].pct_use != NULL) {
+ pcieadm_cmds[cmd].pct_use(stderr);
+ }
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ uint_t cmd;
+
+ pcieadm_progname = basename(argv[0]);
+
+ if (argc < 2) {
+ pcieadm_usage("missing required sub-command");
+ exit(EXIT_USAGE);
+ }
+
+ for (cmd = 0; pcieadm_cmds[cmd].pct_name != NULL; cmd++) {
+ if (strcmp(pcieadm_cmds[cmd].pct_name, argv[1]) == 0) {
+ break;
+ }
+ }
+
+ if (pcieadm_cmds[cmd].pct_name == NULL) {
+ pcieadm_usage("unknown sub-command: %s", argv[1]);
+ exit(EXIT_USAGE);
+ }
+ argc -= 2;
+ argv += 2;
+ optind = 0;
+ pcieadm.pia_cmdtab = &pcieadm_cmds[cmd];
+
+ /*
+ * Set up common things that all of pcieadm needs before dispatching to
+ * a specific sub-command.
+ */
+ pcieadm.pia_pcidb = pcidb_open(PCIDB_VERSION);
+ if (pcieadm.pia_pcidb == NULL) {
+ err(EXIT_FAILURE, "failed to open PCI ID database");
+ }
+
+ pcieadm.pia_root = di_init("/", DINFOCPYALL);
+ if (pcieadm.pia_root == DI_NODE_NIL) {
+ err(EXIT_FAILURE, "failed to initialize devinfo tree");
+ }
+
+ /*
+ * Set up privileges now that we have already opened our core libraries.
+ * We first set up the minimum actual privilege set that we use while
+ * running. We next set up a second privilege set that has additional
+ * privileges that are intersected with the users actual privileges and
+ * are appended to by the underlying command backends.
+ */
+ if ((pcieadm.pia_priv_init = priv_allocset()) == NULL) {
+ err(EXIT_FAILURE, "failed to allocate privilege set");
+ }
+
+ if (getppriv(PRIV_EFFECTIVE, pcieadm.pia_priv_init) != 0) {
+ err(EXIT_FAILURE, "failed to get current privileges");
+ }
+
+ if ((pcieadm.pia_priv_min = priv_allocset()) == NULL) {
+ err(EXIT_FAILURE, "failed to allocate privilege set");
+ }
+
+ if ((pcieadm.pia_priv_eff = priv_allocset()) == NULL) {
+ err(EXIT_FAILURE, "failed to allocate privilege set");
+ }
+
+ /*
+ * Note, PRIV_FILE_READ is not removed from the basic set so that way we
+ * can still open libraries that are required due to lazy loading.
+ */
+ priv_basicset(pcieadm.pia_priv_min);
+ VERIFY0(priv_delset(pcieadm.pia_priv_min, PRIV_FILE_LINK_ANY));
+ VERIFY0(priv_delset(pcieadm.pia_priv_min, PRIV_PROC_INFO));
+ VERIFY0(priv_delset(pcieadm.pia_priv_min, PRIV_PROC_SESSION));
+ VERIFY0(priv_delset(pcieadm.pia_priv_min, PRIV_PROC_FORK));
+ VERIFY0(priv_delset(pcieadm.pia_priv_min, PRIV_NET_ACCESS));
+ VERIFY0(priv_delset(pcieadm.pia_priv_min, PRIV_FILE_WRITE));
+ VERIFY0(priv_delset(pcieadm.pia_priv_min, PRIV_PROC_EXEC));
+ VERIFY0(priv_delset(pcieadm.pia_priv_min, PRIV_PROC_EXEC));
+
+ priv_copyset(pcieadm.pia_priv_min, pcieadm.pia_priv_eff);
+ priv_intersect(pcieadm.pia_priv_init, pcieadm.pia_priv_eff);
+
+ if (setppriv(PRIV_SET, PRIV_EFFECTIVE, pcieadm.pia_priv_min) != 0) {
+ err(EXIT_FAILURE, "failed to reduce privileges");
+ }
+
+ return (pcieadm.pia_cmdtab->pct_func(&pcieadm, argc, argv));
+}
diff --git a/usr/src/cmd/pcieadm/pcieadm.h b/usr/src/cmd/pcieadm/pcieadm.h
new file mode 100644
index 0000000000..b5d44ef970
--- /dev/null
+++ b/usr/src/cmd/pcieadm/pcieadm.h
@@ -0,0 +1,112 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2021 Oxide Computer Company
+ */
+
+#ifndef _PCIEADM_H
+#define _PCIEADM_H
+
+/*
+ * Common definitions for pcieadm(1M).
+ */
+
+#include <libdevinfo.h>
+#include <pcidb.h>
+#include <priv.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct pcieadm pcieadm_t;
+
+typedef struct pcieadm_cmdtab {
+ const char *pct_name;
+ int (*pct_func)(pcieadm_t *, int, char **);
+ void (*pct_use)(FILE *);
+} pcieadm_cmdtab_t;
+
+struct pcieadm {
+ uint_t pia_indent;
+ di_node_t pia_root;
+ const char *pia_devstr;
+ di_node_t pia_devi;
+ di_node_t pia_nexus;
+ pcidb_hdl_t *pia_pcidb;
+ const pcieadm_cmdtab_t *pia_cmdtab;
+ priv_set_t *pia_priv_init;
+ priv_set_t *pia_priv_min;
+ priv_set_t *pia_priv_eff;
+};
+
+typedef struct {
+ void *pdw_arg;
+ int (*pdw_func)(di_node_t, void *);
+} pcieadm_di_walk_t;
+
+/*
+ * Config space related
+ */
+typedef boolean_t (*pcieadm_cfgspace_f)(uint32_t, uint8_t, void *, void *);
+
+/*
+ * Utilities
+ */
+extern void pcieadm_di_walk(pcieadm_t *, pcieadm_di_walk_t *);
+extern void pcieadm_init_cfgspace_kernel(pcieadm_t *, pcieadm_cfgspace_f *,
+ void **);
+extern void pcieadm_fini_cfgspace_kernel(void *);
+extern void pcieadm_init_cfgspace_file(pcieadm_t *, const char *,
+ pcieadm_cfgspace_f *, void **);
+extern void pcieadm_fini_cfgspace_file(void *);
+extern void pcieadm_find_nexus(pcieadm_t *);
+extern void pcieadm_find_dip(pcieadm_t *, const char *);
+extern boolean_t pcieadm_di_node_is_pci(di_node_t);
+
+/*
+ * Output related
+ */
+extern const char *pcieadm_progname;
+extern void pcieadm_indent(void);
+extern void pcieadm_deindent(void);
+extern void pcieadm_print(const char *, ...);
+extern void pcieadm_ofmt_errx(const char *, ...);
+
+/*
+ * Command tabs
+ */
+extern int pcieadm_save_cfgspace(pcieadm_t *, int, char *[]);
+extern void pcieadm_save_cfgspace_usage(FILE *);
+extern int pcieadm_show_cfgspace(pcieadm_t *, int, char *[]);
+extern void pcieadm_show_cfgspace_usage(FILE *);
+extern int pcieadm_show_devs(pcieadm_t *, int, char *[]);
+extern void pcieadm_show_devs_usage(FILE *);
+
+#define EXIT_USAGE 2
+
+/*
+ * Privilege related. Note there are no centralized functions around raising and
+ * lowering privs as that unfortunately makes ROPs more easy to execute.
+ */
+extern void pcieadm_init_privs(pcieadm_t *);
+
+/*
+ * XXX Maybe not here:
+ */
+#define BITX(u, h, l) (((u) >> (l)) & ((1LU << ((h) - (l) + 1LU)) - 1LU))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PCIEADM_H */
diff --git a/usr/src/cmd/pcieadm/pcieadm_cfgspace.c b/usr/src/cmd/pcieadm/pcieadm_cfgspace.c
new file mode 100644
index 0000000000..50d98c5ec9
--- /dev/null
+++ b/usr/src/cmd/pcieadm/pcieadm_cfgspace.c
@@ -0,0 +1,5046 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2021 Oxide Computer Company
+ */
+
+/*
+ * This file contains logic to walk and print a large chunk of configuration
+ * space and many of the capabilities. There are multiple sub-commands that
+ * vector into the same logic (e.g. 'save-cfgspace' and 'show-cfgspace'). In
+ * general, there are a few major goals with this bit of code:
+ *
+ * o Every field should strive to be parsable and therefore selectable for
+ * output. This drove the idea that every field has both a short name and a
+ * human name. The short name is a dot-delineated name. When in parsable
+ * mode, the name will always refer to a single field. However, for
+ * convenience for humans, when not trying to be parsable, we show the
+ * parents in the tree. That is if you specify something like
+ * 'pcie.linkcap.maxspeed', in parsable mode you'll only get that; however,
+ * in non-parsable mode, you'll get an indication of the capability and
+ * register that field was in.
+ *
+ * o Related to the above, parsable mode always outputs a raw, uninterpreted
+ * value. This was done on purpose. Some fields require interpreting multiple
+ * registers to have meaning and long strings aren't always the most useful.
+ *
+ * o Every field isn't always pretty printed. This was generally just a
+ * decision based upon the field itself and how much work it'd be to fit it
+ * into the framework we have. In general, the ones we're mostly guilty of
+ * doing this with are related to cases where there's a scaling value in a
+ * subsequent register. If you find yourself wanting this, feel free to add
+ * it.
+ *
+ * o Currently designated vendor-specific capabilities aren't included here (or
+ * any specific vendor-specific capabilities for that matter). If they are
+ * added, they should follow the same angle of using a name to represent a
+ * sub-capability as we did with HyperTransport.
+ */
+
+#include <err.h>
+#include <strings.h>
+#include <sys/sysmacros.h>
+#include <sys/pci.h>
+#include <sys/pcie.h>
+#include <sys/debug.h>
+#include <ofmt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "pcieadm.h"
+
+typedef enum pcieadm_cfgspace_op {
+ PCIEADM_CFGSPACE_OP_PRINT,
+ PCIEADM_CFGSPACE_OP_WRITE
+} pcieadm_cfgspace_op_t;
+
+typedef enum piceadm_cfgspace_flag {
+ PCIEADM_CFGSPACE_F_PARSE = 1 << 0,
+ PCIEADM_CFGSPACE_F_SHORT = 1 << 1,
+} pcieadm_cfgspace_flags_t;
+
+typedef enum pcieadm_cfgspace_otype {
+ PCIEADM_CFGSPACE_OT_SHORT,
+ PCIEADM_CFGSPACE_OT_HUMAN,
+ PCIEADM_CFGSPACE_OT_VALUE
+} pcieadm_cfgsapce_otype_t;
+
+typedef struct pcieadm_cfgspace_ofmt {
+ const char *pco_base;
+ const char *pco_short;
+ const char *pco_human;
+ uint64_t pco_value;
+ const char *pco_strval;
+} pcieadm_cfgspace_ofmt_t;
+
+typedef enum pcieadm_regdef_val {
+ PRDV_STRVAL,
+ PRDV_BITFIELD,
+ PRDV_HEX
+} pcieadm_regdef_val_t;
+
+typedef struct pcieadm_regdef_addend {
+ uint8_t pra_shift;
+ int64_t pra_addend;
+} pcieadm_regdef_addend_t;
+
+typedef struct pcieadm_regdef {
+ uint8_t prd_lowbit;
+ uint8_t prd_hibit;
+ const char *prd_short;
+ const char *prd_human;
+ pcieadm_regdef_val_t prd_valtype;
+ union {
+ /*
+ * Enough space for up to an 8-bit fields worth of values
+ * (though we expect most to be sparse).
+ */
+ const char *prdv_strval[128];
+ pcieadm_regdef_addend_t prdv_hex;
+ } prd_val;
+} pcieadm_regdef_t;
+
+typedef struct pcieadm_unitdef {
+ const char *pcd_unit;
+ uint32_t pcd_mult;
+} pcieadm_unitdef_t;
+
+typedef struct pcieadm_strmap {
+ const char *psr_str;
+ uint64_t psr_val;
+} pcieadm_strmap_t;
+
+typedef struct pcieadm_cfgspace_filter {
+ const char *pcf_string;
+ size_t pcf_len;
+ boolean_t pcf_used;
+} pcieadm_cfgspace_filter_t;
+
+typedef struct pcieadm_strfilt {
+ struct pcieadm_strfilt *pstr_next;
+ const char *pstr_str;
+ char pstr_curgen[256];
+} pcieadm_strfilt_t;
+
+/*
+ * Data is sized to be large enough that we can hold all of PCIe extended
+ * configuration space.
+ */
+typedef union pcieadm_cfgspace_data {
+ uint8_t pcb_u8[PCIE_CONF_HDR_SIZE];
+ uint32_t pcb_u32[PCIE_CONF_HDR_SIZE / 4];
+} pcieadm_cfgspace_data_t;
+
+typedef struct pcieadm_cfgspace_walk {
+ pcieadm_t *pcw_pcieadm;
+ pcieadm_cfgspace_op_t pcw_op;
+ uint32_t pcw_valid;
+ pcieadm_cfgspace_data_t *pcw_data;
+ uint16_t pcw_capoff;
+ uint32_t pcw_caplen;
+ int pcw_outfd;
+ uint_t pcw_dtype;
+ uint_t pcw_nlanes;
+ uint_t pcw_pcietype;
+ uint_t pcw_nfilters;
+ pcieadm_cfgspace_filter_t *pcw_filters;
+ pcieadm_cfgspace_flags_t pcw_flags;
+ ofmt_handle_t pcw_ofmt;
+ pcieadm_strfilt_t *pcw_filt;
+} pcieadm_cfgspace_walk_t;
+
+void
+pcieadm_strfilt_pop(pcieadm_cfgspace_walk_t *walkp)
+{
+ pcieadm_strfilt_t *filt;
+
+ VERIFY3P(walkp->pcw_filt, !=, NULL);
+ filt = walkp->pcw_filt;
+ walkp->pcw_filt = filt->pstr_next;
+ free(filt);
+}
+
+void
+pcieadm_strfilt_push(pcieadm_cfgspace_walk_t *walkp, const char *str)
+{
+ pcieadm_strfilt_t *filt;
+ size_t len;
+
+ filt = calloc(1, sizeof (*filt));
+ if (filt == NULL) {
+ errx(EXIT_FAILURE, "failed to allocate memory for string "
+ "filter");
+ }
+
+ filt->pstr_str = str;
+ if (walkp->pcw_filt == NULL) {
+ len = strlcat(filt->pstr_curgen, str,
+ sizeof (filt->pstr_curgen));
+ } else {
+ len = snprintf(filt->pstr_curgen, sizeof (filt->pstr_curgen),
+ "%s.%s", walkp->pcw_filt->pstr_curgen, str);
+ filt->pstr_next = walkp->pcw_filt;
+ }
+
+ if (len >= sizeof (filt->pstr_curgen)) {
+ errx(EXIT_FAILURE, "overflowed internal string buffer "
+ "appending %s", str);
+ }
+
+ walkp->pcw_filt = filt;
+}
+
+static boolean_t
+pcieadm_cfgspace_filter(pcieadm_cfgspace_walk_t *walkp, const char *str)
+{
+ char buf[1024];
+ size_t len;
+
+ if (walkp->pcw_nfilters == 0) {
+ return (B_TRUE);
+ }
+
+ if (str == NULL) {
+ return (B_FALSE);
+ }
+
+ if (walkp->pcw_filt != NULL) {
+ len = snprintf(buf, sizeof (buf), "%s.%s",
+ walkp->pcw_filt->pstr_curgen, str);
+ } else {
+ len = snprintf(buf, sizeof (buf), "%s", str);
+ }
+
+ if (len >= sizeof (buf)) {
+ abort();
+ }
+
+ for (uint_t i = 0; i < walkp->pcw_nfilters; i++) {
+ if (strcmp(buf, walkp->pcw_filters[i].pcf_string) == 0) {
+ walkp->pcw_filters[i].pcf_used = B_TRUE;
+ return (B_TRUE);
+ }
+
+ /*
+ * If we're in non-parsable mode, we want to do a little bit
+ * more in a few cases. We want to make sure that we print the
+ * parents of more-specific entries. That is, if someone
+ * specified 'header.command.serr', then we want to print
+ * 'header', and 'header.command'. Similarly, if someone
+ * specifies an individual field, we want to print all of its
+ * subfields, that is asking for 'header.command', really gets
+ * that and all of 'header.command.*'.
+ */
+ if ((walkp->pcw_flags & PCIEADM_CFGSPACE_F_PARSE) != 0) {
+ continue;
+ }
+
+ if (len >= walkp->pcw_filters[i].pcf_len) {
+ if (strncmp(buf, walkp->pcw_filters[i].pcf_string,
+ walkp->pcw_filters[i].pcf_len) == 0 &&
+ buf[walkp->pcw_filters[i].pcf_len] == '.') {
+ return (B_TRUE);
+ }
+ } else {
+ if (strncmp(buf, walkp->pcw_filters[i].pcf_string,
+ len) == 0 &&
+ walkp->pcw_filters[i].pcf_string[len] == '.') {
+ return (B_TRUE);
+ }
+ }
+ }
+
+ return (B_FALSE);
+}
+
+static boolean_t
+pcieadm_cfgspace_ofmt_cb(ofmt_arg_t *ofarg, char *buf, uint_t buflen)
+{
+ pcieadm_cfgspace_ofmt_t *pco = ofarg->ofmt_cbarg;
+
+ switch (ofarg->ofmt_id) {
+ case PCIEADM_CFGSPACE_OT_SHORT:
+ if (snprintf(buf, buflen, "%s.%s", pco->pco_base,
+ pco->pco_short) >= buflen) {
+ return (B_FALSE);
+ }
+ break;
+ case PCIEADM_CFGSPACE_OT_HUMAN:
+ if (strlcpy(buf, pco->pco_human, buflen) >= buflen) {
+ return (B_FALSE);
+ }
+ break;
+ case PCIEADM_CFGSPACE_OT_VALUE:
+ if (pco->pco_strval != NULL) {
+ if (strlcpy(buf, pco->pco_strval, buflen) >= buflen) {
+ return (B_FALSE);
+ }
+ } else {
+ if (snprintf(buf, buflen, "0x%" PRIx64,
+ pco->pco_value) >= buflen) {
+ return (B_FALSE);
+ }
+ }
+ break;
+ default:
+ abort();
+ }
+
+ return (B_TRUE);
+}
+
+
+static const ofmt_field_t pcieadm_cfgspace_ofmt[] = {
+ { "SHORT", 30, PCIEADM_CFGSPACE_OT_SHORT, pcieadm_cfgspace_ofmt_cb },
+ { "HUMAN", 30, PCIEADM_CFGSPACE_OT_HUMAN, pcieadm_cfgspace_ofmt_cb },
+ { "VALUE", 20, PCIEADM_CFGSPACE_OT_VALUE, pcieadm_cfgspace_ofmt_cb },
+ { NULL, 0, 0, NULL }
+};
+
+static void
+pcieadm_cfgspace_print_parse(pcieadm_cfgspace_walk_t *walkp,
+ const char *sname, const char *human, uint64_t value)
+{
+ pcieadm_cfgspace_ofmt_t pco;
+
+ VERIFY3P(walkp->pcw_filt, !=, NULL);
+ pco.pco_base = walkp->pcw_filt->pstr_curgen;
+ pco.pco_short = sname;
+ pco.pco_human = human;
+ pco.pco_value = value;
+ pco.pco_strval = NULL;
+ ofmt_print(walkp->pcw_ofmt, &pco);
+}
+
+typedef struct pcieadm_cfgspace_print pcieadm_cfgspace_print_t;
+typedef void (*pcieadm_cfgspace_print_f)(pcieadm_cfgspace_walk_t *,
+ pcieadm_cfgspace_print_t *, void *);
+
+struct pcieadm_cfgspace_print {
+ uint8_t pcp_off;
+ uint8_t pcp_len;
+ const char *pcp_short;
+ const char *pcp_human;
+ pcieadm_cfgspace_print_f pcp_print;
+ void *pcp_arg;
+};
+
+static void
+pcieadm_field_printf(pcieadm_cfgspace_walk_t *walkp, const char *shortf,
+ const char *humanf, uint64_t val, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (!pcieadm_cfgspace_filter(walkp, shortf))
+ return;
+
+ if (walkp->pcw_ofmt != NULL) {
+ pcieadm_cfgspace_print_parse(walkp, shortf, humanf, val);
+ return;
+ }
+
+ if (walkp->pcw_pcieadm->pia_indent > 0) {
+ (void) printf("%*s", walkp->pcw_pcieadm->pia_indent, "");
+ }
+
+ if ((walkp->pcw_flags & PCIEADM_CFGSPACE_F_SHORT) != 0) {
+ (void) printf("|--> %s (%s.%s): ", humanf,
+ walkp->pcw_filt->pstr_curgen, shortf);
+ } else {
+ (void) printf("|--> %s: ", humanf);
+ }
+
+ va_start(ap, fmt);
+ (void) vprintf(fmt, ap);
+ va_end(ap);
+
+}
+
+static void
+pcieadm_cfgspace_printf(pcieadm_cfgspace_walk_t *walkp,
+ pcieadm_cfgspace_print_t *print, uint64_t val, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (!pcieadm_cfgspace_filter(walkp, print->pcp_short))
+ return;
+
+ if (walkp->pcw_ofmt != NULL) {
+ pcieadm_cfgspace_print_parse(walkp, print->pcp_short,
+ print->pcp_human, val);
+ return;
+ }
+
+ if (walkp->pcw_pcieadm->pia_indent > 0) {
+ (void) printf("%*s", walkp->pcw_pcieadm->pia_indent, "");
+ }
+
+ if ((walkp->pcw_flags & PCIEADM_CFGSPACE_F_SHORT) != 0) {
+ (void) printf("%s (%s.%s): ", print->pcp_human,
+ walkp->pcw_filt->pstr_curgen, print->pcp_short);
+ } else {
+ (void) printf("%s: ", print->pcp_human);
+ }
+
+ va_start(ap, fmt);
+ (void) vprintf(fmt, ap);
+ va_end(ap);
+}
+
+static void
+pcieadm_cfgspace_puts(pcieadm_cfgspace_walk_t *walkp,
+ pcieadm_cfgspace_print_t *print, const char *str)
+{
+ if (!pcieadm_cfgspace_filter(walkp, print->pcp_short))
+ return;
+
+ if (walkp->pcw_ofmt != NULL) {
+ pcieadm_cfgspace_ofmt_t pco;
+
+ VERIFY3P(walkp->pcw_filt, !=, NULL);
+ pco.pco_base = walkp->pcw_filt->pstr_curgen;
+ pco.pco_short = print->pcp_short;
+ pco.pco_human = print->pcp_human;
+ pco.pco_strval = str;
+ ofmt_print(walkp->pcw_ofmt, &pco);
+ return;
+ }
+
+ if (walkp->pcw_pcieadm->pia_indent > 0) {
+ (void) printf("%*s", walkp->pcw_pcieadm->pia_indent, "");
+ }
+
+ if ((walkp->pcw_flags & PCIEADM_CFGSPACE_F_SHORT) != 0) {
+ (void) printf("%s (%s.%s): %s\n", print->pcp_human,
+ walkp->pcw_filt->pstr_curgen, print->pcp_short, str);
+ } else {
+ (void) printf("%s: %s\n", print->pcp_human, str);
+ }
+}
+
+static uint64_t
+pcieadm_cfgspace_extract(pcieadm_cfgspace_walk_t *walkp,
+ pcieadm_cfgspace_print_t *print)
+{
+ uint32_t val = 0;
+
+ VERIFY3U(print->pcp_len, <=, 8);
+ VERIFY3U(print->pcp_off + print->pcp_len + walkp->pcw_capoff, <=,
+ walkp->pcw_valid);
+ for (uint8_t i = print->pcp_len; i > 0; i--) {
+ val <<= 8;
+ val |= walkp->pcw_data->pcb_u8[walkp->pcw_capoff +
+ print->pcp_off + i - 1];
+ }
+
+ return (val);
+}
+
+static uint16_t
+pcieadm_cfgspace_extract_u16(pcieadm_cfgspace_walk_t *walkp,
+ pcieadm_cfgspace_print_t *print)
+{
+ VERIFY(print->pcp_len == 2);
+ return ((uint16_t)pcieadm_cfgspace_extract(walkp, print));
+}
+
+static void
+pcieadm_cfgspace_print_unit(pcieadm_cfgspace_walk_t *walkp,
+ pcieadm_cfgspace_print_t *print, void *arg)
+{
+ pcieadm_unitdef_t *unit = arg;
+ uint64_t rawval = pcieadm_cfgspace_extract(walkp, print);
+ uint64_t val = rawval;
+
+ if (unit->pcd_mult > 1) {
+ val *= unit->pcd_mult;
+ }
+ pcieadm_cfgspace_printf(walkp, print, rawval, "0x%" PRIx64 " %s%s\n",
+ val, unit->pcd_unit, val != 1 ? "s" : "");
+}
+
+static void
+pcieadm_cfgspace_print_regdef(pcieadm_cfgspace_walk_t *walkp,
+ pcieadm_cfgspace_print_t *print, void *arg)
+{
+ pcieadm_regdef_t *regdef = arg;
+ uint64_t val = pcieadm_cfgspace_extract(walkp, print);
+
+ pcieadm_cfgspace_printf(walkp, print, val, "0x%" PRIx64 "\n", val);
+
+ pcieadm_indent();
+ pcieadm_strfilt_push(walkp, print->pcp_short);
+
+ for (regdef = arg; regdef->prd_short != NULL; regdef++) {
+ uint32_t nbits = regdef->prd_hibit - regdef->prd_lowbit + 1UL;
+ uint32_t bitmask = (1UL << nbits) - 1UL;
+ uint64_t regval = (val >> regdef->prd_lowbit) & bitmask;
+ const char *strval;
+ uint64_t actval;
+
+ if (!pcieadm_cfgspace_filter(walkp, regdef->prd_short)) {
+ continue;
+ }
+
+ switch (regdef->prd_valtype) {
+ case PRDV_STRVAL:
+ strval = regdef->prd_val.prdv_strval[regval];
+ if (strval == NULL) {
+ strval = "reserved";
+ }
+ pcieadm_field_printf(walkp, regdef->prd_short,
+ regdef->prd_human, regval, "%s (0x%" PRIx64 ")\n",
+ strval, regval << regdef->prd_lowbit);
+ break;
+ case PRDV_HEX:
+ actval = regval;
+ if (regdef->prd_val.prdv_hex.pra_shift > 0) {
+ actval <<= regdef->prd_val.prdv_hex.pra_shift;
+ }
+ actval += regdef->prd_val.prdv_hex.pra_addend;
+
+ pcieadm_field_printf(walkp, regdef->prd_short,
+ regdef->prd_human, regval, "0x% " PRIx64 "\n",
+ actval);
+ break;
+ case PRDV_BITFIELD:
+ pcieadm_field_printf(walkp, regdef->prd_short,
+ regdef->prd_human, regval, "0x%" PRIx64 "\n",
+ regval << regdef->prd_lowbit);
+
+ if (walkp->pcw_ofmt == NULL) {
+ pcieadm_indent();
+ for (uint32_t i = 0; i < nbits; i++) {
+ if (((1 << i) & regval) == 0)
+ continue;
+ pcieadm_print("|--> %s (0x%x)\n",
+ regdef->prd_val.prdv_strval[i],
+ 1UL << (i + regdef->prd_lowbit));
+ }
+ pcieadm_deindent();
+ }
+ break;
+ }
+ }
+
+ pcieadm_strfilt_pop(walkp);
+ pcieadm_deindent();
+}
+
+static void
+pcieadm_cfgspace_print_strmap(pcieadm_cfgspace_walk_t *walkp,
+ pcieadm_cfgspace_print_t *print, void *arg)
+{
+ pcieadm_strmap_t *strmap = arg;
+ uint64_t val = pcieadm_cfgspace_extract(walkp, print);
+ const char *str = "reserved";
+
+ for (uint_t i = 0; strmap[i].psr_str != NULL; i++) {
+ if (strmap[i].psr_val == val) {
+ str = strmap[i].psr_str;
+ break;
+ }
+ }
+
+ pcieadm_cfgspace_printf(walkp, print, val, "0x%x -- %s\n", val, str);
+}
+
+static void
+pcieadm_cfgspace_print_hex(pcieadm_cfgspace_walk_t *walkp,
+ pcieadm_cfgspace_print_t *print, void *arg)
+{
+ uint64_t val = pcieadm_cfgspace_extract(walkp, print);
+
+ pcieadm_cfgspace_printf(walkp, print, val, "0x%" PRIx64 "\n", val);
+}
+
+static void
+pcieadm_cfgspace_print_vendor(pcieadm_cfgspace_walk_t *walkp,
+ pcieadm_cfgspace_print_t *print, void *arg)
+{
+ pcidb_vendor_t *vend;
+ uint16_t vid = pcieadm_cfgspace_extract_u16(walkp, print);
+
+ vend = pcidb_lookup_vendor(walkp->pcw_pcieadm->pia_pcidb, vid);
+ if (vend != NULL) {
+ pcieadm_cfgspace_printf(walkp, print, vid, "0x%x -- %s\n", vid,
+ pcidb_vendor_name(vend));
+ } else {
+ pcieadm_cfgspace_printf(walkp, print, vid, "0x%x\n", vid);
+ }
+}
+
+static void
+pcieadm_cfgspace_print_device(pcieadm_cfgspace_walk_t *walkp,
+ pcieadm_cfgspace_print_t *print, void *arg)
+{
+ pcidb_device_t *dev;
+ uint16_t did = pcieadm_cfgspace_extract_u16(walkp, print);
+ uint16_t vid = walkp->pcw_data->pcb_u8[PCI_CONF_VENID] +
+ (walkp->pcw_data->pcb_u8[PCI_CONF_VENID + 1] << 8);
+
+ dev = pcidb_lookup_device(walkp->pcw_pcieadm->pia_pcidb, vid, did);
+ if (dev != NULL) {
+ pcieadm_cfgspace_printf(walkp, print, did, "0x%x -- %s\n", did,
+ pcidb_device_name(dev));
+ } else {
+ pcieadm_cfgspace_printf(walkp, print, did, "0x%x\n", did);
+ }
+}
+
+/*
+ * To print out detailed information about a subsystem vendor or device, we need
+ * all of the information about the vendor and device due to the organization of
+ * the PCI IDs db.
+ */
+static void
+pcieadm_cfgspace_print_subid(pcieadm_cfgspace_walk_t *walkp,
+ pcieadm_cfgspace_print_t *print, void *arg)
+{
+ uint16_t vid = walkp->pcw_data->pcb_u8[PCI_CONF_VENID] +
+ (walkp->pcw_data->pcb_u8[PCI_CONF_VENID + 1] << 8);
+ uint16_t did = walkp->pcw_data->pcb_u8[PCI_CONF_DEVID] +
+ (walkp->pcw_data->pcb_u8[PCI_CONF_DEVID + 1] << 8);
+ uint16_t svid = walkp->pcw_data->pcb_u8[PCI_CONF_SUBVENID] +
+ (walkp->pcw_data->pcb_u8[PCI_CONF_SUBVENID + 1] << 8);
+ uint16_t sdid = walkp->pcw_data->pcb_u8[PCI_CONF_SUBSYSID] +
+ (walkp->pcw_data->pcb_u8[PCI_CONF_SUBSYSID + 1] << 8);
+ uint16_t val = pcieadm_cfgspace_extract_u16(walkp, print);
+ boolean_t isvendor = print->pcp_off == PCI_CONF_SUBVENID;
+
+ if (isvendor) {
+ pcidb_vendor_t *vend;
+ vend = pcidb_lookup_vendor(walkp->pcw_pcieadm->pia_pcidb,
+ svid);
+ if (vend != NULL) {
+ pcieadm_cfgspace_printf(walkp, print, val,
+ "0x%x -- %s\n", val, pcidb_vendor_name(vend));
+ } else {
+ pcieadm_cfgspace_printf(walkp, print, val,
+ "0x%x\n", val);
+ }
+ } else {
+ pcidb_subvd_t *subvd;
+ subvd = pcidb_lookup_subvd(walkp->pcw_pcieadm->pia_pcidb, vid,
+ did, svid, sdid);
+ if (subvd != NULL) {
+ pcieadm_cfgspace_printf(walkp, print, val,
+ "0x%x -- %s\n", val, pcidb_subvd_name(subvd));
+ } else {
+ pcieadm_cfgspace_printf(walkp, print, val, "0x%x\n",
+ val);
+ }
+ }
+}
+
+/*
+ * The variable natures of BARs is a pain. This makes printing this out and the
+ * fields all a bit gross.
+ */
+static void
+pcieadm_cfgspace_print_bars(pcieadm_cfgspace_walk_t *walkp,
+ pcieadm_cfgspace_print_t *print, void *arg)
+{
+ uint32_t *barp = &walkp->pcw_data->pcb_u32[(walkp->pcw_capoff +
+ print->pcp_off) / 4];
+ char barname[32];
+ const char *typestrs[2] = { "Memory Space", "I/O Space" };
+
+ for (uint_t i = 0; i < print->pcp_len / 4; i++) {
+ uint_t type;
+ (void) snprintf(barname, sizeof (barname), "%s%u",
+ print->pcp_short, i);
+
+ type = barp[i] & PCI_BASE_SPACE_M;
+
+ if (pcieadm_cfgspace_filter(walkp, barname) &&
+ walkp->pcw_ofmt == NULL) {
+ if ((walkp->pcw_flags & PCIEADM_CFGSPACE_F_SHORT) !=
+ 0) {
+ pcieadm_print("%s %u (%s.%s)\n",
+ print->pcp_human, i,
+ walkp->pcw_filt->pstr_curgen, barname);
+ } else {
+ pcieadm_print("%s %u\n", print->pcp_human, i);
+ }
+ }
+
+ pcieadm_strfilt_push(walkp, barname);
+ pcieadm_indent();
+
+ pcieadm_field_printf(walkp, "space", "Space", type,
+ "%s (0x%x)\n", typestrs[type], type);
+
+ if (type == PCI_BASE_SPACE_IO) {
+ uint32_t addr = barp[i] & PCI_BASE_IO_ADDR_M;
+
+ pcieadm_field_printf(walkp, "addr", "Address", addr,
+ "0x%" PRIx32 "\n", addr);
+ } else {
+ uint8_t type, pre;
+ uint64_t addr;
+ const char *locstr;
+
+ type = barp[i] & PCI_BASE_TYPE_M;
+ pre = barp[i] & PCI_BASE_PREF_M;
+ addr = barp[i] & PCI_BASE_M_ADDR_M;
+
+ if (type == PCI_BASE_TYPE_ALL) {
+ addr += (uint64_t)barp[i+1] << 32;
+ i++;
+ }
+
+ pcieadm_field_printf(walkp, "addr", "Address", addr,
+ "0x%" PRIx64 "\n", addr);
+
+ switch (type) {
+ case PCI_BASE_TYPE_MEM:
+ locstr = "32-bit";
+ break;
+ case PCI_BASE_TYPE_LOW:
+ locstr = "Sub-1 MiB";
+ break;
+ case PCI_BASE_TYPE_ALL:
+ locstr = "64-bit";
+ break;
+ case PCI_BASE_TYPE_RES:
+ default:
+ locstr = "Reserved";
+ break;
+ }
+
+ pcieadm_field_printf(walkp, "addr", "Address", addr,
+ "%s (0x%x)\n", locstr, type >> 1);
+ pcieadm_field_printf(walkp, "prefetch", "Prefetchable",
+ pre != 0, "%s (0x%x)\n", pre != 0 ? "yes" : "no",
+ pre != 0);
+ }
+
+ pcieadm_deindent();
+ pcieadm_strfilt_pop(walkp);
+ }
+}
+
+static void
+pcieadm_cfgspace_print_ecv(pcieadm_cfgspace_walk_t *walkp,
+ pcieadm_cfgspace_print_t *print, void *arg)
+{
+ uint16_t bitlen, nwords;
+
+ if (BITX(walkp->pcw_data->pcb_u8[walkp->pcw_capoff + 4], 5, 5) == 0) {
+ return;
+ }
+
+ bitlen = walkp->pcw_data->pcb_u8[walkp->pcw_capoff + 5];
+ if (bitlen == 0) {
+ bitlen = 256;
+ }
+
+ nwords = bitlen / 32;
+ if ((bitlen % 8) != 0) {
+ nwords++;
+ }
+
+ for (uint16_t i = 0; i < nwords; i++) {
+ char tshort[32], thuman[128];
+ pcieadm_cfgspace_print_t p;
+
+ (void) snprintf(tshort, sizeof (tshort), "ecv%u", i);
+ (void) snprintf(thuman, sizeof (thuman), "Egress Control "
+ "Vector %u", i);
+ p.pcp_off = print->pcp_off + i * 4;
+ p.pcp_len = 4;
+ p.pcp_short = tshort;
+ p.pcp_human = thuman;
+ p.pcp_print = pcieadm_cfgspace_print_hex;
+ p.pcp_arg = NULL;
+
+ p.pcp_print(walkp, &p, p.pcp_arg);
+ }
+}
+
+static void
+pcieadm_cfgspace_print_dpa_paa(pcieadm_cfgspace_walk_t *walkp,
+ pcieadm_cfgspace_print_t *print, void *arg)
+{
+ uint8_t nents;
+
+ nents = BITX(walkp->pcw_data->pcb_u8[walkp->pcw_capoff + 4], 4, 0) + 1;
+ if (nents == 0) {
+ return;
+ }
+
+ for (uint8_t i = 0; i < nents; i++) {
+ char tshort[32], thuman[128];
+ pcieadm_cfgspace_print_t p;
+
+ (void) snprintf(tshort, sizeof (tshort), "%s%u",
+ print->pcp_short, i);
+ (void) snprintf(thuman, sizeof (thuman), "%s %u",
+ print->pcp_human, i);
+
+ p.pcp_off = print->pcp_off + i;
+ p.pcp_len = 1;
+ p.pcp_short = tshort;
+ p.pcp_human = thuman;
+ p.pcp_print = pcieadm_cfgspace_print_hex;
+ p.pcp_arg = NULL;
+
+ p.pcp_print(walkp, &p, p.pcp_arg);
+ }
+}
+
+/*
+ * Config Space Header Table Definitions
+ */
+static pcieadm_regdef_t pcieadm_regdef_command[] = {
+ { 0, 0, "io", "I/O Space", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 1, 1, "mem", "Memory Space", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 2, 2, "bus", "Bus Master", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 3, 3, "spec", "Special Cycle", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 4, 4, "mwi", "Memory Write and Invalidate", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 5, 5, "vga", "VGA Palette Snoop", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 6, 6, "per", "Parity Error Response", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 7, 7, "idsel", "IDSEL Stepping/Wait Cycle Control", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 8, 8, "serr", "SERR# Enable", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } }, },
+ { 9, 9, "fbtx", "Fast Back-to-Back Transactions", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } }, },
+ { 10, 10, "intx", "Interrupt X", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "enabled", "disabled" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_status[] = {
+ { 0, 0, "imm", "Immediate Readiness", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } }, },
+ { 3, 3, "istat", "Interrupt Status", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "not pending", "pending" } }, },
+ { 4, 4, "capsup", "Capabilities List", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } }, },
+ { 5, 5, "66mhz", "66 MHz Capable", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } }, },
+ { 7, 7, "fbtxcap", "Fast Back-to-Back Capable", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } }, },
+ { 8, 8, "mdperr", "Master Data Parity Error", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no error", "error detected" } }, },
+ { 9, 10, "devsel", "DEVSEL# Timing", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "fast", "medium", "slow",
+ "reserved" } } },
+ { 11, 11, "sta", "Signaled Target Abort", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 12, 12, "rta", "Received Target Abort", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 13, 13, "rma", "Received Master Abort", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 14, 14, "sse", "Signaled System Error", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 15, 15, "dpe", "Detected Parity Error", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { -1, -1, NULL }
+};
+
+/*
+ * It might be interesting to translate these into numbers at a future point.
+ */
+static pcieadm_regdef_t pcieadm_regdef_class[] = {
+ { 16, 23, "class", "Class Code", PRDV_HEX },
+ { 7, 15, "sclass", "Sub-Class Code", PRDV_HEX },
+ { 0, 7, "pi", "Programming Interface", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_bridge_iobase[] = {
+ { 0, 3, "cap", "Addressing Capability", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "16-bit", "32-bit" } } },
+ { 4, 7, "base", "Base", PRDV_HEX,
+ .prd_val = { .prdv_hex = { 12 } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_bridge_iolim[] = {
+ { 0, 3, "cap", "Addressing Capability", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "16-bit", "32-bit" } } },
+ { 4, 7, "limit", "Limit", PRDV_HEX,
+ .prd_val = { .prdv_hex = { 12, 0xfff } } },
+ { -1, -1, NULL }
+};
+
+
+static pcieadm_regdef_t pcieadm_regdef_bridgests[] = {
+ { 5, 5, "66mhz", "66 MHz", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 7, 7, "fastb2b", "Fast Back-to-Back Transactions", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 8, 8, "mdperr", "Master Data Parity Error", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no error", "error detected" } } },
+ { 9, 10, "devsel", "DEVSEL# Timing", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "fast", "medium", "slow" } } },
+ { 11, 11, "sta", "Signaled Target Abort", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no abort", "aborted" } } },
+ { 12, 12, "rta", "Received Target Abort", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no abort", "aborted" } } },
+ { 13, 13, "rma", "Received Master Abort", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no abort", "aborted" } } },
+ { 14, 14, "rsyserr", "Received System Error", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no error", "error received" } } },
+ { 15, 15, "dperr", "Detected Parity Error", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no error", "error detected" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_bridge_membase[] = {
+ { 4, 16, "base", "Base", PRDV_HEX,
+ .prd_val = { .prdv_hex = { 20 } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_bridge_memlim[] = {
+ { 4, 16, "limit", "Limit", PRDV_HEX,
+ .prd_val = { .prdv_hex = { 20, 0xfffff } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_bridge_pfbase[] = {
+ { 0, 3, "cap", "Addressing Capability", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "32-bit", "64-bit" } } },
+ { 4, 16, "base", "Base", PRDV_HEX,
+ .prd_val = { .prdv_hex = { 20 } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_bridge_pflim[] = {
+ { 0, 3, "cap", "Addressing Capability", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "32-bit", "64-bit" } } },
+ { 4, 16, "limit", "Limit", PRDV_HEX,
+ .prd_val = { .prdv_hex = { 20, 0xfffff } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_bridge_ctl[] = {
+ { 0, 0, "perrresp", "Parity Error Response", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 1, 1, "serr", "SERR#", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 2, 2, "isa", "ISA", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 3, 3, "vga", "VGA", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 4, 4, "vgadec", "VGA 16-bit Decode", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "10-bit", "16-bit" } } },
+ { 5, 5, "mabort", "Master Abort", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 6, 6, "secrst", "Secondary Bus Reset", PRDV_HEX },
+ { 7, 7, "fastb2b", "Fast Back-to-Back Transactions", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 8, 8, "pridisc", "Primary Discard Timer", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "2^15 cycles", "2^10 cycles" } } },
+ { 9, 9, "secdisc", "Secondary Discard Timer", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "2^15 cycles", "2^10 cycles" } } },
+ { 10, 10, "disctimer", "Discard Timer Error", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 11, 11, "discserr", "Discard Timer SERR#", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_unitdef_t pcieadm_unitdef_cache = {
+ "byte", 4
+};
+
+static pcieadm_unitdef_t pcieadm_unitdef_latreg = { "cycle" };
+
+static pcieadm_regdef_t pcieadm_regdef_header[] = {
+ { 0, 6, "layout", "Header Layout", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "Device", "Bridge", "PC Card" } } },
+ { 7, 7, "mfd", "Multi-Function Device", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_bist[] = {
+ { 0, 3, "code", "Completion Code", PRDV_HEX },
+ { 6, 6, "start", "Start BIST", PRDV_HEX },
+ { 7, 7, "cap", "BIST Capable", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_exprom[] = {
+ { 0, 0, "enable", "Enable", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 11, 31, "addr", "Base Address", PRDV_HEX,
+ .prd_val = { .prdv_hex = { 21 } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_strmap_t pcieadm_strmap_ipin[] = {
+ { "none", 0 },
+ { "INTA", PCI_INTA },
+ { "INTB", PCI_INTB },
+ { "INTC", PCI_INTC },
+ { "INTD", PCI_INTD },
+ { NULL }
+};
+
+
+static pcieadm_cfgspace_print_t pcieadm_cfgspace_type0[] = {
+ { 0x0, 2, "vendor", "Vendor ID", pcieadm_cfgspace_print_vendor },
+ { 0x2, 2, "device", "Device ID", pcieadm_cfgspace_print_device },
+ { 0x4, 2, "command", "Command", pcieadm_cfgspace_print_regdef,
+ pcieadm_regdef_command },
+ { 0x6, 2, "status", "Status", pcieadm_cfgspace_print_regdef,
+ pcieadm_regdef_status },
+ { 0x8, 1, "revision", "Revision ID", pcieadm_cfgspace_print_hex },
+ { 0x9, 3, "class", "Class Code", pcieadm_cfgspace_print_regdef,
+ pcieadm_regdef_class },
+ { 0xc, 1, "cache", "Cache Line Size", pcieadm_cfgspace_print_unit,
+ &pcieadm_unitdef_cache },
+ { 0xd, 1, "latency", "Latency Timer", pcieadm_cfgspace_print_unit,
+ &pcieadm_unitdef_latreg },
+ { 0xe, 1, "type", "Header Type", pcieadm_cfgspace_print_regdef,
+ pcieadm_regdef_header },
+ { 0xf, 1, "bist", "BIST", pcieadm_cfgspace_print_regdef,
+ pcieadm_regdef_bist },
+ { 0x10, 24, "bar", "Base Address Register",
+ pcieadm_cfgspace_print_bars },
+ { 0x28, 4, "cis", "Cardbus CIS Pointer", pcieadm_cfgspace_print_hex },
+ { 0x2c, 2, "subvid", "Subsystem Vendor ID",
+ pcieadm_cfgspace_print_subid },
+ { 0x2e, 2, "subdev", "Subsystem Device ID",
+ pcieadm_cfgspace_print_subid },
+ { 0x30, 4, "rom", "Expansion ROM", pcieadm_cfgspace_print_regdef,
+ pcieadm_regdef_exprom },
+ { 0x34, 1, "cap", "Capabilities Pointer", pcieadm_cfgspace_print_hex },
+ { 0x3c, 1, "iline", "Interrupt Line", pcieadm_cfgspace_print_hex },
+ { 0x3d, 1, "ipin", "Interrupt Pin", pcieadm_cfgspace_print_strmap,
+ pcieadm_strmap_ipin },
+ { 0x3e, 1, "gnt", "Min_Gnt", pcieadm_cfgspace_print_hex },
+ { 0x3f, 1, "lat", "Min_Lat", pcieadm_cfgspace_print_hex },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cfgspace_type1[] = {
+ { 0x0, 2, "vendor", "Vendor ID", pcieadm_cfgspace_print_vendor },
+ { 0x2, 2, "device", "Device ID", pcieadm_cfgspace_print_device },
+ { 0x4, 2, "command", "Command", pcieadm_cfgspace_print_regdef,
+ pcieadm_regdef_command },
+ { 0x6, 2, "status", "Status", pcieadm_cfgspace_print_regdef,
+ pcieadm_regdef_status },
+ { 0x8, 1, "revision", "Revision ID", pcieadm_cfgspace_print_hex },
+ { 0x9, 3, "class", "Class Code", pcieadm_cfgspace_print_regdef,
+ pcieadm_regdef_class },
+ { 0xc, 1, "cache", "Cache Line Size", pcieadm_cfgspace_print_unit,
+ &pcieadm_unitdef_cache },
+ { 0xd, 1, "latency", "Latency Timer", pcieadm_cfgspace_print_unit,
+ &pcieadm_unitdef_latreg },
+ { 0xe, 1, "type", "Header Type", pcieadm_cfgspace_print_regdef,
+ pcieadm_regdef_header },
+ { 0xf, 1, "bist", "BIST", pcieadm_cfgspace_print_regdef,
+ pcieadm_regdef_bist },
+ { 0x10, 8, "bar", "Base Address Register",
+ pcieadm_cfgspace_print_bars },
+ { PCI_BCNF_PRIBUS, 1, "pribus", "Primary Bus Number",
+ pcieadm_cfgspace_print_hex },
+ { PCI_BCNF_SECBUS, 1, "secbus", "Secondary Bus Number",
+ pcieadm_cfgspace_print_hex },
+ { PCI_BCNF_SUBBUS, 1, "subbus", "Subordinate Bus Number",
+ pcieadm_cfgspace_print_hex },
+ { PCI_BCNF_LATENCY_TIMER, 1, "latency2", "Secondary Latency timer",
+ pcieadm_cfgspace_print_unit, &pcieadm_unitdef_latreg },
+ { PCI_BCNF_IO_BASE_LOW, 1, "iobase", "I/O Base Low",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_bridge_iobase },
+ { PCI_BCNF_IO_LIMIT_LOW, 1, "iolimit", "I/O Limit Low",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_bridge_iolim },
+ { PCI_BCNF_SEC_STATUS, 2, "status2", "Secondary Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_bridgests },
+ { PCI_BCNF_MEM_BASE, 2, "membase", "Memory Base",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_bridge_membase },
+ { PCI_BCNF_MEM_LIMIT, 2, "memlimit", "Memory Limit",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_bridge_memlim },
+ { PCI_BCNF_PF_BASE_LOW, 2, "pfbase", "Prefetchable Memory Base",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_bridge_pfbase },
+ { PCI_BCNF_PF_LIMIT_LOW, 2, "pflimit", "Prefetchable Memory Limit",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_bridge_pflim },
+ { PCI_BCNF_PF_BASE_HIGH, 4, "pfbasehi",
+ "Prefetchable Base Upper 32 bits",
+ pcieadm_cfgspace_print_hex },
+ { PCI_BCNF_PF_LIMIT_HIGH, 4, "pflimihi",
+ "Prefetchable Limit Upper 32 bits",
+ pcieadm_cfgspace_print_hex },
+ { PCI_BCNF_IO_BASE_HI, 2, "iobasehi", "I/O Base Upper 16 bits",
+ pcieadm_cfgspace_print_hex },
+ { PCI_BCNF_IO_LIMIT_HI, 2, "iobasehi", "I/O Limit Upper 16 bits",
+ pcieadm_cfgspace_print_hex },
+ { PCI_BCNF_CAP_PTR, 1, "cap", "Capabilities Pointer",
+ pcieadm_cfgspace_print_hex },
+ { PCI_BCNF_ROM, 4, "rom", "Expansion ROM",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_exprom },
+ { PCI_BCNF_ILINE, 1, "iline", "Interrupt Line",
+ pcieadm_cfgspace_print_hex },
+ { PCI_BCNF_IPIN, 1, "ipin", "Interrupt Pin",
+ pcieadm_cfgspace_print_strmap, pcieadm_strmap_ipin },
+ { PCI_BCNF_BCNTRL, 2, "bctl", "Bridge Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_bridge_ctl },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cfgspace_unknown[] = {
+ { 0x0, 2, "vendor", "Vendor ID", pcieadm_cfgspace_print_vendor },
+ { 0x2, 2, "device", "Device ID", pcieadm_cfgspace_print_device },
+ { 0x8, 1, "revision", "Revision ID", pcieadm_cfgspace_print_hex },
+ { 0xe, 1, "type", "Header Type", pcieadm_cfgspace_print_regdef,
+ pcieadm_regdef_header },
+ { -1, -1, NULL }
+};
+
+/*
+ * Power Management Capability Version 3. Note versions two and three seem to be
+ * the same, but are used to indicate compliance to different revisions of the
+ * PCI power management specification.
+ */
+static pcieadm_regdef_t pcieadm_regdef_pmcap[] = {
+ { 0, 2, "vers", "Version", PRDV_HEX },
+ { 3, 3, "clock", "PME Clock", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "not required", "required" } } },
+ { 4, 4, "irrd0", "Immediate Readiness on Return to D0", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 5, 5, "dsi", "Device Specific Initialization", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 6, 8, "auxcur", "Auxiliary Current", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "0", "55 mA", "100 mA", "160 mA",
+ "220 mA", "270 mA", "320 mA", "375 mA" } } },
+ { 9, 9, "d1", "D1", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 10, 10, "d2", "D2", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 11, 15, "pme", "PME Support", PRDV_BITFIELD,
+ .prd_val = { .prdv_strval = { "D0", "D1", "D2", "D3hot",
+ "D3cold" } } },
+ { -1, -1, NULL }
+};
+
+
+static pcieadm_cfgspace_print_t pcieadm_cap_pcipm_v3[] = {
+ { PCI_PMCAP, 2, "pmcap", "Power Management Capabilities",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pmcap },
+ { -1, -1, NULL }
+};
+
+/*
+ * PCI Bridge Subsystem Capability
+ */
+static pcieadm_cfgspace_print_t pcieadm_cap_bridge_subsys[] = {
+ { 0x4, 2, "subvid", "Subsystem Vendor ID", pcieadm_cfgspace_print_hex },
+ { 0x6, 2, "subdev", "Subsystem Device ID", pcieadm_cfgspace_print_hex },
+ { -1, -1, NULL }
+};
+
+/*
+ * MSI Capability
+ */
+static pcieadm_regdef_t pcieadm_regdef_msictrl[] = {
+ { 0, 0, "enable", "MSI Enable", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 1, 3, "mmsgcap", "Multiple Message Capable", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "1 vector", "2 vectors",
+ "4 vectors", "8 vectors", "16 vectors", "32 vectors" } } },
+ { 4, 6, "mmsgen", "Multiple Message Enabled", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "1 vector", "2 vectors",
+ "4 vectors", "8 vectors", "16 vectors", "32 vectors" } } },
+ { 7, 7, "addr64", "64-bit Address Capable", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 8, 8, "pvm", "Per-Vector Masking Capable", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 9, 9, "extmdcap", "Extended Message Data Capable",
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 10, 10, "extmden", "extended Message Data Enable",
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cap_msi_32[] = {
+ { PCI_MSI_CTRL, 2, "ctrl", "Message Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_msictrl },
+ { PCI_MSI_ADDR_OFFSET, 4, "addr", "Message Address",
+ pcieadm_cfgspace_print_hex },
+ { PCI_MSI_32BIT_DATA, 2, "data", "Message Data",
+ pcieadm_cfgspace_print_hex },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cap_msi_32ext[] = {
+ { PCI_MSI_CTRL, 2, "ctrl", "Message Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_msictrl },
+ { PCI_MSI_ADDR_OFFSET, 4, "addr", "Message Address",
+ pcieadm_cfgspace_print_hex },
+ { PCI_MSI_32BIT_DATA, 2, "data", "Message Data",
+ pcieadm_cfgspace_print_hex },
+ { PCI_MSI_32BIT_EXTDATA, 2, "extdata", "Extended Message Data",
+ pcieadm_cfgspace_print_hex },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cap_msi_32pvm[] = {
+ { PCI_MSI_CTRL, 2, "ctrl", "Message Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_msictrl },
+ { PCI_MSI_ADDR_OFFSET, 4, "addr", "Message Address",
+ pcieadm_cfgspace_print_hex },
+ { PCI_MSI_32BIT_DATA, 2, "data", "Message Data",
+ pcieadm_cfgspace_print_hex },
+ { PCI_MSI_32BIT_EXTDATA, 2, "extdata", "Extended Message Data",
+ pcieadm_cfgspace_print_hex },
+ { PCI_MSI_32BIT_MASK, 4, "mask", "Mask Bits",
+ pcieadm_cfgspace_print_hex },
+ { PCI_MSI_32BIT_PENDING, 4, "pend", "Pending Bits",
+ pcieadm_cfgspace_print_hex },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cap_msi_64[] = {
+ { PCI_MSI_CTRL, 2, "ctrl", "Message Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_msictrl },
+ { PCI_MSI_ADDR_OFFSET, 4, "addr", "Message Address",
+ pcieadm_cfgspace_print_hex },
+ { PCI_MSI_64BIT_ADDR, 4, "upadd", "Upper Message Address",
+ pcieadm_cfgspace_print_hex },
+ { PCI_MSI_64BIT_DATA, 2, "data", "Message Data",
+ pcieadm_cfgspace_print_hex },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cap_msi_64ext[] = {
+ { PCI_MSI_CTRL, 2, "ctrl", "Message Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_msictrl },
+ { PCI_MSI_ADDR_OFFSET, 4, "addr", "Message Address",
+ pcieadm_cfgspace_print_hex },
+ { PCI_MSI_64BIT_ADDR, 4, "upadd", "Upper Message Address",
+ pcieadm_cfgspace_print_hex },
+ { PCI_MSI_64BIT_DATA, 2, "data", "Message Data",
+ pcieadm_cfgspace_print_hex },
+ { PCI_MSI_64BIT_EXTDATA, 2, "extdata", "Extended Message Data",
+ pcieadm_cfgspace_print_hex },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cap_msi_64pvm[] = {
+ { PCI_MSI_CTRL, 2, "ctrl", "Message Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_msictrl },
+ { PCI_MSI_ADDR_OFFSET, 4, "addr", "Message Address",
+ pcieadm_cfgspace_print_hex },
+ { PCI_MSI_64BIT_ADDR, 4, "upadd", "Upper Message Address",
+ pcieadm_cfgspace_print_hex },
+ { PCI_MSI_64BIT_DATA, 2, "data", "Message Data",
+ pcieadm_cfgspace_print_hex },
+ { PCI_MSI_64BIT_EXTDATA, 2, "extdata", "Extended Message Data",
+ pcieadm_cfgspace_print_hex },
+ { PCI_MSI_64BIT_MASKBITS, 4, "mask", "Mask Bits",
+ pcieadm_cfgspace_print_hex },
+ { PCI_MSI_64BIT_PENDING, 4, "pend", "Pending Bits",
+ pcieadm_cfgspace_print_hex },
+ { -1, -1, NULL }
+};
+
+/*
+ * MSI-X Capability
+ */
+static pcieadm_regdef_t pcieadm_regdef_msixctrl[] = {
+ { 0, 10, "size", "Table Size", PRDV_HEX,
+ .prd_val = { .prdv_hex = { 0, 1 } } },
+ { 14, 14, "mask", "Function Mask", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unmasked", "masked" } } },
+ { 15, 15, "enable", "MSI-X Enable", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_msixtable[] = {
+ { 0, 2, "bir", "Table BIR", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "BAR 0", "BAR 1", "BAR 2", "BAR 3",
+ "BAR 4", "BAR 5" } } },
+ { 3, 31, "offset", "Table Offset", PRDV_HEX,
+ .prd_val = { .prdv_hex = { 3 } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_msixpba[] = {
+ { 0, 2, "bir", "PBA BIR", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "BAR 0", "BAR 1", "BAR 2", "BAR 3",
+ "BAR 4", "BAR 5" } } },
+ { 3, 31, "offset", "PBA Offset", PRDV_HEX,
+ .prd_val = { .prdv_hex = { 3 } } },
+ { -1, -1, NULL }
+};
+
+
+static pcieadm_cfgspace_print_t pcieadm_cap_msix[] = {
+ { PCI_MSIX_CTRL, 2, "ctrl", "Control Register",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_msixctrl },
+ { PCI_MSIX_TBL_OFFSET, 4, "table", "Table Offset",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_msixtable },
+ { PCI_MSIX_PBA_OFFSET, 4, "pba", "PBA Offset",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_msixpba },
+ { -1, -1, NULL }
+};
+
+/*
+ * PCI Express Capability
+ */
+static pcieadm_regdef_t pcieadm_regdef_pcie_cap[] = {
+ { 0, 3, "vers", "Version", PRDV_HEX },
+ { 4, 7, "type", "Device/Port Type", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "PCIe Endpoint",
+ "Legacy PCIe Endpoint", NULL, NULL,
+ "Root Port of PCIe Root Complex",
+ "Upstream Port of PCIe Switch",
+ "Downstream Port of PCIe Switch",
+ "PCIe to PCI/PCI-X Bridge",
+ "PCI/PCI-x to PCIe Bridge",
+ "RCiEP",
+ "Root Complex Event Collector" } } },
+ { 8, 8, "slot", "Slot Implemented", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "No", "Yes" } } },
+ { 9, 13, "intno", "Interrupt Message Number", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_pcie_devcap[] = {
+ { 0, 2, "mps", "Max Payload Size Supported", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "128 bytes", "256 bytes",
+ "512 bytes", "1024 byes", "2048 bytes", "4096 bytes" } } },
+ { 3, 4, "pfunc", "Phantom Functions Supported", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "No", "1-bit", "2-bits",
+ "3-bits" } } },
+ { 5, 5, "exttag", "Extended Tag Field", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "5-bit", "8-bit" } } },
+ { 6, 8, "l0slat", "L0s Acceptable Latency", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "64 ns", "128 ns", "256 ns",
+ "512 ns", "1 us", "2 us", "4 us", "No limit" } } },
+ { 9, 11, "l1lat", "L1 Acceptable Latency", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "1 us", "2 us", "4 us", "8 us",
+ "16 us", "32 us", "64 us", "No limit" } } },
+ { 15, 15, "rber", "Role Based Error Reporting", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 16, 16, "errcor", "ERR_COR Subclass", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 18, 25, "csplv", "Captured Slot Power Limit", PRDV_HEX },
+ { 26, 27, "cspls", "Captured Slot Power Limit Scale", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "1.0x", "0.1x", "0.01x",
+ "0.001x" } } },
+ { 28, 28, "flr", "Function Level Reset", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_pcie_devctl[] = {
+ { 0, 0, "corerr", "Correctable Error Reporting", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 1, 1, "nferr", "Non-Fatal Error Reporting", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 2, 2, "ferr", "Fatal Error Reporting", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 3, 3, "unsupreq", "Unsupported Request Reporting", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 4, 4, "relord", "Relaxed Ordering", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 5, 7, "mps", "Max Payload Size", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "128 bytes", "256 bytes",
+ "512 bytes", "1024 byes", "2048 bytes", "4096 bytes" } } },
+ { 8, 8, "exttag", "Extended Tag Field", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 9, 9, "pfunc", "Phantom Functions", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 9, 9, "auxpm", "Aux Power PM", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 11, 11, "nosnoop", "No Snoop", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 12, 14, "mrrs", "Max Read Request Size", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "128 bytes", "256 bytes",
+ "512 bytes", "1024 byes", "2048 bytes", "4096 bytes" } } },
+ { 15, 15, "bcrflr", "Bridge Configuration Retry / Function Level Reset",
+ PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_pcie_devsts[] = {
+ { 0, 0, "corerr", "Correctable Error Detected", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 1, 1, "nferr", "Non-Fatal Error Detected", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 2, 2, "ferr", "Fatal Error Detected", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 3, 3, "unsupreq", "Unsupported Request Detected", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 4, 4, "auxpm", "AUX Power Detected", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 5, 5, "txpend", "Transactions Pending", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 6, 6, "eprd", "Emergency Power Reduction Detected", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_pcie_linkcap[] = {
+ { 0, 3, "maxspeed", "Maximum Link Speed", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { NULL, "2.5 GT/s", "5.0 GT/s",
+ "8.0 GT/s", "16.0 GT/s", "32.0 GT/s" } } },
+ { 4, 9, "maxwidth", "Maximum Link Width", PRDV_HEX },
+ { 10, 11, "aspm", "ASPM Support", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "None", "L0s", "L1", "L0s/L1" } } },
+ { 12, 14, "l0slat", "L0s Exit Latency", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "<64ns", "64-128ns", "128-256ns",
+ "256-512ns", "512ns-1us", "1-2us", "2-4us", ">4us" } } },
+ { 15, 17, "l1lat", "L1 Exit Latency", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "<1us", "1-2us", "2-4us", "4-8us",
+ "8-16us", "16-32us" "32-64us", ">64us" } } },
+ { 18, 18, "clockpm", "Clock Power Management", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 19, 19, "supdown", "Surprise Down Error Reporting", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 20, 20, "dlact", "Data Link Layer Active Reporting", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 21, 21, "linkbw", "Link Bandwidth Notification Capability",
+ PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 22, 22, "aspmcomp", "ASPM Optionality Compliance", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "not compliant", "compliant" } } },
+ { 24, 31, "portno", "Port Number", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_pcie_linkctl[] = {
+ { 0, 1, "aspmctl", "ASPM Control", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "None", "L0s", "L1", "L0s/L1" } } },
+ { 3, 3, "rcb", "Read Completion Boundary", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "64 byte", "128 byte" } } },
+ { 4, 4, "disable", "Link Disable", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "not force disabled",
+ "force disabled" } } },
+ { 5, 5, "retrain", "Retrain Link", PRDV_HEX },
+ { 6, 6, "ccc", "Common Clock Configuration", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "asynchronous", "common" } } },
+ { 7, 7, "extsync", "Extended Sync", PRDV_HEX,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 8, 8, "clkpm", "Clock Power Management", PRDV_HEX,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 9, 9, "hwawd", "Hardware Autonomous Width", PRDV_HEX,
+ .prd_val = { .prdv_strval = { "enabled", "disabled" } } },
+ { 10, 10, "linkbwint", "Link Bandwidth Management Interrupt", PRDV_HEX,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 11, 11, "linkabwint", "Link Autonomous Bandwidth Interrupt", PRDV_HEX,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 14, 15, "drs", "DRS Signaling Control", PRDV_HEX,
+ .prd_val = { .prdv_strval = { "not reported", "Interrupt enabled",
+ "DRS->FRS enabled" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_pcie_linksts[] = {
+ { 0, 3, "speed", "Link Speed", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { NULL, "2.5 GT/s", "5.0 GT/s",
+ "8.0 GT/s", "16.0 GT/s", "32.0 GT/s" } } },
+ { 4, 9, "width", "Link Width", PRDV_HEX },
+ { 11, 11, "training", "Link Training", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 12, 12, "slotclk", "Slot Clock Configuration", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "asynchronous", "common" } } },
+ { 13, 13, "dllact", "Data Link Layer Link Active", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 14, 14, "linkbw", "Link Bandwidth Management Status", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no change", "change occurred" } } },
+ { 15, 15, "linkabw", "Link Autonomous Bandwidth Status", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no change", "change occurred" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_pcie_slotcap[] = {
+ { 0, 0, "attnbtn", "Attention Button Present", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 1, 1, "pwrctrl", "Power Controller Present", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 2, 2, "mrlsen", "MRL Sensor Present", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 3, 3, "attnind", "Attention Indicator Present", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 4, 4, "powind", "Power Indicator Present", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 5, 5, "hpsup", "Hot-Plug Surprise", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 6, 6, "hpcap", "Hot-Plug Capable ", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 7, 14, "slotplv", "Slot Power Limit Value", PRDV_HEX },
+ { 15, 16, "slotpls", "Slot Power Limit Scale", PRDV_HEX },
+ { 17, 17, "emi", "Electromechanical Interlock Present",
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 18, 18, "ncc", "No Command Completed", PRDV_HEX,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 19, 31, "slotno", "Physical Slot Number", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_pcie_slotctl[] = {
+ { 0, 0, "attnbtn", "Attention Button Pressed", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 1, 1, "powflt", "Power Fault Detected", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 2, 2, "mrlsen", "MRL Sensor Changed", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 3, 3, "presdet", "Presence Detect Changed", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 4, 4, "ccmpltint", "Command Complete Interrupt", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "Enabled" } } },
+ { 5, 5, "hpi", "Hot Plug Interrupt Enable", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 6, 7, "attnind", "Attention Indicator Control", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { NULL, "on", "blink", "off" } } },
+ { 8, 9, "powin", "Power Indicator Control", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { NULL, "on", "blink", "off" } } },
+ { 10, 10, "pwrctrl", "Power Controller Control", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "power on", "power off" } } },
+ { 11, 11, "emi", "Electromechanical Interlock Control", PRDV_HEX },
+ { 12, 12, "dll", "Data Link Layer State Changed", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 13, 13, "autopowdis", "Auto Slot Power Limit", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "enabled", "disabled" } } },
+ { 14, 14, "ibpddis", "In-Band PD", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "enabled", "disabled" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_pcie_slotsts[] = {
+ { 0, 0, "attnbtn", "Attention Button Pressed", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 1, 1, "powflt", "Power Fault Detected", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 2, 2, "mrlsen", "MRL Sensor Changed", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 3, 3, "presdet", "Presence Detect Changed", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 4, 4, "ccmplt", "Command Complete", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 5, 5, "mrlsen", "MRL Sensor State", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "closed", "open" } } },
+ { 6, 6, "presdet", "Presence Detect State", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "not present", "present" } } },
+ { 7, 7, "emi", "Electromechanical Interlock", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disengaged", "engaged" } } },
+ { 8, 8, "dll", "Data Link Layer State Changed", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_pcie_rootcap[] = {
+ { 0, 0, "syscorerr", "System Error on Correctable Error", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 1, 1, "sysnonftl", "System Error on Non-Fatal Error", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 2, 2, "sysfatal", "System Error on Fatal Error", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 3, 3, "pmeie", "PME Interrupt", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 4, 4, "crssw", "CRS Software Visibility", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_pcie_rootctl[] = {
+ { 0, 0, "crssw", "CRS Software Visibility", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_pcie_rootsts[] = {
+ { 0, 15, "pmereqid", "PME Requester ID", PRDV_HEX },
+ { 16, 16, "pmests", "PME Status", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "deasserted", "asserted" } } },
+ { 17, 17, "pmepend", "PME Pending", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_pcie_devcap2[] = {
+ { 0, 3, "cmpto", "Completion Timeout Ranges Supported", PRDV_BITFIELD,
+ .prd_val = { .prdv_strval = { "50us-10ms", "10ms-250ms",
+ "250ms-4s", "4s-64s" } } },
+ { 4, 4, "cmptodis", "Completion Timeout Disable", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 5, 5, "ari", "ARI Forwarding", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 6, 6, "atomroute", "AtomicOp Routing", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 7, 7, "atom32", "32-bit AtomicOp Completer", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 8, 8, "atom64", "64-bit AtomicOp Completer", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 9, 9, "cas128", "128-bit CAS Completer", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 10, 10, "norelord", "No Ro-enabld PR-PR Passing", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 11, 11, "ltr", "LTR Mechanism", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 12, 13, "tph", "TPH Completer", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "TPH supported",
+ NULL, "TPH and Extended TPH supported" } } },
+ { 14, 15, "lncls", "LN System CLS", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported",
+ "LN with 64-byte cachelines", "LN with 128-byte cachelines" } } },
+ { 16, 16, "tag10comp", "10-bit Tag Completer", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 17, 17, "tag10req", "10-bit Tag Requester", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 18, 19, "obff", "OBFF", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "Message Signaling",
+ "WAKE# Signaling", "WAKE# and Message Signaling" } } },
+ { 20, 20, "extfmt", "Extended Fmt Field Supported", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 21, 21, "eetlp", "End-End TLP Prefix Supported", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 22, 23, "maxeetlp", "Max End-End TLP Prefixes", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "4", "1", "2", "3" } } },
+ { 24, 25, "empr", "Emergency Power Reduction", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported",
+ "supported, device-specific",
+ "supported, from factor or device-specific" } } },
+ { 21, 21, "emprinit",
+ "Emergency Power Reduction Initialization Required", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 31, 31, "frs", "Function Readiness Status", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_pcie_devctl2[] = {
+ { 0, 3, "cmpto", "Completion Timeout", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "50us-50ms", "50us-100us",
+ "1ms-10ms", NULL, NULL, "16ms-55ms", "65ms-210ms", NULL, NULL,
+ "260ms-900ms", "1s-3.5s", NULL, NULL, "4s-13s", "17s-64s" } } },
+ { 4, 4, "cmptodis", "Completion Timeout Disabled", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "not disabled", "disabled" } } },
+ { 5, 5, "ari", "ARI Forwarding", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 6, 6, "atomreq", "AtomicOp Requester", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 7, 7, "atomblock", "AtomicOp Egress Blocking", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unblocked", "blocked" } } },
+ { 8, 8, "idoreq", "ID-Based Ordering Request", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 9, 9, "idocomp", "ID-Based Ordering Completion", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 10, 10, "ltr", "LTR Mechanism", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 11, 11, "empowred", "Emergency Power Reduction", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "not requested", "requested" } } },
+ { 12, 12, "tag10req", "10-bit Tag Requester", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 13, 14, "obff", "OBFF", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "message signaling - A",
+ "message signaling - B", "WAKE# signaling" } } },
+ { 15, 15, "eetlpblk", "End-End TLP Prefix Blocking", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unblocked", "blocked" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_pcie_devsts2[] = {
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_pcie_linkcap2[] = {
+ { 1, 7, "supspeeds", "Supported Link Speeds", PRDV_BITFIELD,
+ .prd_val = { .prdv_strval = { "2.5 GT/s", "5.0 GT/s", "8.0 GT/s",
+ "16.0 GT/s", "32.0 GT/s" } } },
+ { 8, 8, "crosslink", "Crosslink", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 9, 15, "skposgen", "Lower SKP OS Generation Supported Speeds Vector",
+ PRDV_BITFIELD,
+ .prd_val = { .prdv_strval = { "2.5 GT/s", "5.0 GT/s", "8.0 GT/s",
+ "16.0 GT/s", "32.0 GT/s" } } },
+ { 16, 22, "skposrecv", "Lower SKP OS Reception Supported Speeds Vector",
+ PRDV_BITFIELD,
+ .prd_val = { .prdv_strval = { "2.5 GT/s", "5.0 GT/s", "8.0 GT/s",
+ "16.0 GT/s", "32.0 GT/s" } } },
+ { 23, 23, "retimedet", "Retimer Presence Detect Supported", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 24, 24, "retime2det", "Two Retimers Presence Detect Supported",
+ PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 31, 31, "drs", "Device Readiness Status", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_pcie_linkctl2[] = {
+ { 0, 3, "targspeed", "Target Link Speed", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { NULL, "2.5 GT/s", "5.0 GT/s",
+ "8.0 GT/s", "16.0 GT/s", "32.0 GT/s" } } },
+ { 4, 4, "comp", "Enter Compliance", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 5, 5, "hwautosp", "Hardware Autonomous Speed Disable", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "not disabled", "disabled" } } },
+ { 6, 6, "seldeemph", "Selectable De-emphasis", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "-6 dB", "-3.5 dB" } } },
+ { 7, 9, "txmarg", "TX Margin", PRDV_HEX },
+ { 10, 10, "modcomp", "Enter Modified Compliance", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 11, 11, "compsos", "Compliance SOS",
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 12, 15, "compemph", "Compliance Preset/De-emphasis", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_pcie_linksts2[] = {
+ { 0, 0, "curdeemph", "Current De-emphasis Level", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "-6 dB", "-3.5 dB" } } },
+ { 1, 1, "eq8comp", "Equalization 8.0 GT/s Complete", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 2, 2, "eq8p1comp", "Equalization 8.0 GT/s Phase 1", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsuccessful", "successful" } } },
+ { 3, 3, "eq8p2comp", "Equalization 8.0 GT/s Phase 2", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsuccessful", "successful" } } },
+ { 4, 4, "eq8p3comp", "Equalization 8.0 GT/s Phase 3", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsuccessful", "successful" } } },
+ { 5, 5, "linkeq8req", "Link Equalization Request 8.0 GT/s", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "not requested", "requested" } } },
+ { 6, 6, "retimedet", "Retimer Presence Detected", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 7, 7, "retime2det", "Two Retimers Presence Detected", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 8, 9, "crosslink", "Crosslink Resolution", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "upstream port",
+ "downstream port", "incomplete" } } },
+ { 12, 14, "dscomppres", "Downstream Component Presence", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "link down - undetermined",
+ "link down - not present", "link down - present", NULL,
+ "link up - present", "link up - present and DRS" } } },
+ { 15, 15, "drsrx", "DRS Message Received", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_pcie_slotcap2[] = {
+ { 0, 0, "ibpddis", "In-Band PD Disable", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_pcie_slotctl2[] = {
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_pcie_slotsts2[] = {
+ { -1, -1, NULL }
+};
+
+
+static pcieadm_cfgspace_print_t pcieadm_cap_pcie_v1[] = {
+ { PCIE_PCIECAP, 2, "cap", "Capability Register",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_cap },
+ { PCIE_DEVCAP, 4, "devcap", "Device Capabilities",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devcap },
+ { PCIE_DEVSTS, 2, "devsts", "Device Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devsts },
+ { PCIE_LINKCAP, 4, "linkcap", "Link Capabilities",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linkcap },
+ { PCIE_LINKCTL, 2, "linkctl", "Link Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linkctl },
+ { PCIE_LINKSTS, 2, "linksts", "Link Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linksts },
+ { PCIE_SLOTCAP, 4, "slotcap", "Slot Capabilities",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotcap },
+ { PCIE_SLOTCTL, 2, "slotctl", "Slot Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotctl },
+ { PCIE_SLOTSTS, 2, "slotsts", "Slot Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotsts },
+ { PCIE_ROOTCTL, 2, "rootctl", "Root control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_rootctl },
+ { PCIE_ROOTCAP, 2, "rootcap", "Root Capabilities",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_rootcap },
+ { PCIE_ROOTSTS, 4, "rootsts", "Root Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_rootsts },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cap_pcie_v2[] = {
+ { PCIE_PCIECAP, 2, "cap", "Capability Register",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_cap },
+ { PCIE_DEVCAP, 4, "devcap", "Device Capabilities",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devcap },
+ { PCIE_DEVCTL, 2, "devctl", "Device Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devctl },
+ { PCIE_DEVSTS, 2, "devsts", "Device Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devsts },
+ { PCIE_LINKCAP, 4, "linkcap", "Link Capabilities",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linkcap },
+ { PCIE_LINKCTL, 2, "linkctl", "Link Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linkctl },
+ { PCIE_LINKSTS, 2, "linksts", "Link Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linksts },
+ { PCIE_SLOTCAP, 4, "slotcap", "Slot Capabilities",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotcap },
+ { PCIE_SLOTCTL, 2, "slotctl", "Slot Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotctl },
+ { PCIE_SLOTSTS, 2, "slotsts", "Slot Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotsts },
+ { PCIE_ROOTCTL, 2, "rootctl", "Root Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_rootctl },
+ { PCIE_ROOTCAP, 2, "rootcap", "Root Capabilities",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_rootcap },
+ { PCIE_ROOTSTS, 4, "rootsts", "Root Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_rootsts },
+ { PCIE_DEVCAP2, 4, "devcap2", "Device Capabilities 2",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devcap2 },
+ { PCIE_DEVCTL2, 2, "devctl2", "Device Control 2",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devctl2 },
+ { PCIE_DEVSTS2, 2, "devsts2", "Device Status 2",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devsts2 },
+ { PCIE_LINKCAP2, 4, "linkcap2", "Link Capabilities 2",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linkcap2 },
+ { PCIE_LINKCTL2, 2, "linkctl2", "Link Control 2",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linkctl2 },
+ { PCIE_LINKSTS2, 2, "linksts2", "Link Status 2",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linksts2 },
+ { PCIE_SLOTCAP2, 4, "slotcap2", "Slot Capabilities 2",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotcap2 },
+ { PCIE_SLOTCTL2, 2, "slotctl2", "Slot Control 2",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotctl2 },
+ { PCIE_SLOTSTS2, 2, "slotsts2", "Slot Status 2",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotsts2 },
+ { -1, -1, NULL }
+};
+
+/*
+ * PCIe Extended Capability Header
+ */
+static pcieadm_regdef_t pcieadm_regdef_pcie_caphdr[] = {
+ { 0, 15, "capid", "Capability ID", PRDV_HEX },
+ { 16, 19, "version", "Capability Version", PRDV_HEX },
+ { 20, 32, "offset", "Next Capability Offset", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+/*
+ * VPD Capability
+ */
+static pcieadm_regdef_t pcieadm_regdef_vpd_addr[] = {
+ { 0, 14, "addr", "VPD Address", PRDV_HEX },
+ { 15, 15, "flag", "Flag", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cap_vpd[] = {
+ { 0x2, 2, "addr", "VPD Address Register",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_vpd_addr },
+ { 0x4, 4, "data", "VPD Data", pcieadm_cfgspace_print_hex },
+ { -1, -1, NULL }
+};
+
+/*
+ * SATA Capability per AHCI 1.3.1
+ */
+static pcieadm_regdef_t pcieadm_regdef_sata_cr0[] = {
+ { 0, 3, "minrev", "Minor Revision", PRDV_HEX },
+ { 4, 7, "majrev", "Major Revision", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_sata_cr1[] = {
+ { 0, 3, "bar", "BAR Location", PRDV_HEX,
+ .prd_val = { .prdv_hex = { 2 } } },
+ { 4, 23, "offset", "BAR Offset", PRDV_HEX,
+ .prd_val = { .prdv_hex = { 2 } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cap_sata[] = {
+ { 0x2, 2, "satacr0", "SATA Capability Register 0",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_sata_cr0 },
+ { 0x4, 4, "satacr1", "SATA Capability Register 1",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_sata_cr1 },
+ { -1, -1, NULL }
+};
+
+/*
+ * Debug Capability per EHCI
+ */
+static pcieadm_regdef_t pcieadm_regdef_debug[] = {
+ { 0, 12, "offset", "BAR Offset", PRDV_HEX },
+ { 13, 15, "bar", "BAR Location ", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { NULL, "BAR 0", "BAR 1", "BAR 2",
+ "BAR 3", "BAR 4", "BAR 5" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cap_debug[] = {
+ { 0x2, 2, "port", "Debug Port",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_debug },
+ { -1, -1, NULL }
+};
+
+/*
+ * AER Capability
+ */
+static pcieadm_regdef_t pcieadm_regdef_aer_ue[] = {
+ { 4, 4, "dlp", "Data Link Protocol Error", PRDV_HEX },
+ { 5, 5, "sde", "Surprise Down Error", PRDV_HEX },
+ { 12, 12, "ptlp", "Poisoned TLP Received", PRDV_HEX },
+ { 13, 13, "fcp", "Flow Control Protocol Error", PRDV_HEX },
+ { 14, 14, "cto", "Completion Timeout", PRDV_HEX },
+ { 15, 15, "cab", "Completion Abort", PRDV_HEX },
+ { 16, 16, "unco", "Unexpected Completion", PRDV_HEX },
+ { 17, 17, "rxov", "Receiver Overflow", PRDV_HEX },
+ { 18, 18, "maltlp", "Malformed TLP", PRDV_HEX },
+ { 19, 19, "ecrc", "ECRC Error", PRDV_HEX },
+ { 20, 20, "usuprx", "Unsupported Request Error", PRDV_HEX },
+ { 21, 21, "acs", "ACS Violation", PRDV_HEX },
+ { 22, 22, "ueint", "Uncorrectable Internal Error", PRDV_HEX },
+ { 23, 23, "mcbtlp", "MC Blocked TLP", PRDV_HEX },
+ { 24, 24, "atoomeb", "AtomicOp Egress Blocked", PRDV_HEX },
+ { 25, 25, "tlppb", "TLP Prefix Blocked Error", PRDV_HEX },
+ { 26, 26, "ptlpeb", "Poisoned TLP Egress Blocked", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_aer_ce[] = {
+ { 0, 0, "rxerr", "Receiver Error", PRDV_HEX },
+ { 6, 6, "badtlp", "Bad TLP", PRDV_HEX },
+ { 7, 7, "baddllp", "Bad DLLP", PRDV_HEX },
+ { 8, 8, "replayro", "REPLAY_NUM Rollover", PRDV_HEX },
+ { 12, 12, "rtto", "Replay timer Timeout", PRDV_HEX },
+ { 13, 13, "advnfe", "Advisory Non-Fatal Error", PRDV_HEX },
+ { 14, 14, "ceint", "Correctable Internal Error", PRDV_HEX },
+ { 15, 15, "headlov", "Header Log Overflow", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_aer_ctrl[] = {
+ { 0, 4, "feptr", "First Error Pointer", PRDV_HEX },
+ { 5, 5, "ecgencap", "ECRC Generation Capable", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 6, 6, "ecgenen", "ECRC Generation Enable", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 7, 7, "ecchkcap", "ECRC Check Capable", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 8, 8, "ecchken", "ECRC Check Enable", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_aer_rootcom[] = {
+ { 0, 0, "corerr", "Correctable Error Reporting", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 1, 1, "nferr", "Non-Fatal Error Reporting", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 2, 2, "faterr", "Fatal Error Reporting", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_aer_rootsts[] = {
+ { 0, 0, "errcor", "ERR_COR Received", PRDV_HEX },
+ { 1, 1, "merrcor", "Multiple ERR_COR Received", PRDV_HEX },
+ { 2, 2, "errfnf", "ERR_FATAL/NONFATAL Received", PRDV_HEX },
+ { 3, 3, "merrfnf", "Multiple ERR_FATAL/NONFATAL Received", PRDV_HEX },
+ { 4, 4, "fuefat", "First Uncorrectable Fatal", PRDV_HEX },
+ { 5, 5, "nferrrx", "Non-Fatal Error Messages Received", PRDV_HEX },
+ { 6, 6, "faterrx", "Fatal Error Messages Received", PRDV_HEX },
+ { 7, 8, "errcorsc", "ERR_COR Subclass", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "ECS Legacy", "ECS SIG_SFW",
+ "ECS SIG_OS", "ECS Extended" } } },
+ { 27, 31, "inum", "Advanced Error Interrupt Message", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_aer_esi[] = {
+ { 0, 15, "errcorr", "ERR_COR Source", PRDV_HEX },
+ { 16, 31, "errfnf", "ERR_FATAL/NONFATAL Source", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_aer_secue[] = {
+ { 0, 0, "taosc", "Target-Abort on Split Completion", PRDV_HEX },
+ { 1, 1, "maosc", "Master-Abort on Split Completion", PRDV_HEX },
+ { 2, 2, "rxta", "Received Target-Abort", PRDV_HEX },
+ { 3, 3, "rxma", "Received Master-Abort", PRDV_HEX },
+ { 5, 5, "unsce", "Unexpected Split Completion Error", PRDV_HEX },
+ { 6, 6, "uescmd", "Uncorrectable Split Completion Message Data Error",
+ PRDV_HEX },
+ { 7, 7, "uede", "Uncorrectable Data Error", PRDV_HEX },
+ { 8, 8, "ueattre", "Uncorrectable Attribute Error", PRDV_HEX },
+ { 9, 9, "ueaddre", "Uncorrectable Address Error", PRDV_HEX },
+ { 10, 10, "dtdte", "Delayed Transaction Discard Timer Expired",
+ PRDV_HEX },
+ { 11, 11, "perr", "PERR# Assertion", PRDV_HEX },
+ { 12, 12, "serr", "SERR# Assertion", PRDV_HEX },
+ { 13, 13, "internal", "Internal Bridge Error", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_aer_secctl[] = {
+ { 0, 4, "feptr", "Secondary Uncorrectable First Error Pointer",
+ PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cap_aer_v1[] = {
+ { PCIE_AER_CAP, 4, "caphdr", "Capability Header",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
+ { PCIE_AER_UCE_STS, 4, "uestatus", "Uncorrectable Error Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ue },
+ { PCIE_AER_UCE_MASK, 4, "uemask", "Uncorrectable Error Mask",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ue },
+ { PCIE_AER_UCE_SERV, 4, "ueserv", "Uncorrectable Error Severity",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ue },
+ { PCIE_AER_CE_STS, 4, "cestatus", "Correctable Error Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ce },
+ { PCIE_AER_CE_MASK, 4, "cemask", "Correctable Error Mask",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ce },
+ { PCIE_AER_CTL, 4, "ctrl", "Advanced Error Capabilities and Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ctrl },
+ { PCIE_AER_HDR_LOG + 4, 4, "hl0", "Header Log 0",
+ pcieadm_cfgspace_print_hex },
+ { PCIE_AER_HDR_LOG + 8, 4, "hl1", "Header Log 1",
+ pcieadm_cfgspace_print_hex },
+ { PCIE_AER_HDR_LOG + 12, 4, "hl2", "Header Log 2",
+ pcieadm_cfgspace_print_hex },
+ { PCIE_AER_HDR_LOG + 12, 4, "hl3", "Header Log 3",
+ pcieadm_cfgspace_print_hex },
+ { PCIE_AER_CTL, 4, "rootcmd", "Root Error Command",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_rootcom },
+ { PCIE_AER_RE_STS, 4, "rootsts", "Root Error Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_rootsts },
+ { PCIE_AER_CE_SRC_ID, 4, "esi", "Error Source Identification",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_esi },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cap_aer_v2[] = {
+ { PCIE_AER_CAP, 4, "caphdr", "Capability Header",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
+ { PCIE_AER_UCE_STS, 4, "uestatus", "Uncorrectable Error Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ue },
+ { PCIE_AER_UCE_MASK, 4, "uemask", "Uncorrectable Error Mask",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ue },
+ { PCIE_AER_UCE_SERV, 4, "ueserv", "Uncorrectable Error Severity",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ue },
+ { PCIE_AER_CE_STS, 4, "cestatus", "Correctable Error Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ce },
+ { PCIE_AER_CE_MASK, 4, "cemask", "Correctable Error Mask",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ce },
+ { PCIE_AER_CTL, 4, "ctrl", "Advanced Error Capabilities and Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ctrl },
+ { PCIE_AER_HDR_LOG + 4, 4, "hl0", "Header Log 0",
+ pcieadm_cfgspace_print_hex },
+ { PCIE_AER_HDR_LOG + 8, 4, "hl1", "Header Log 1",
+ pcieadm_cfgspace_print_hex },
+ { PCIE_AER_HDR_LOG + 12, 4, "hl2", "Header Log 2",
+ pcieadm_cfgspace_print_hex },
+ { PCIE_AER_HDR_LOG + 12, 4, "hl3", "Header Log 3",
+ pcieadm_cfgspace_print_hex },
+ { PCIE_AER_CTL, 4, "rootcmd", "Root Error Command",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_rootcom },
+ { PCIE_AER_RE_STS, 4, "rootsts", "Root Error Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_rootsts },
+ { PCIE_AER_TLP_PRE_LOG, 4, "tlplog0", "TLP Prefix Log 0",
+ pcieadm_cfgspace_print_hex },
+ { PCIE_AER_TLP_PRE_LOG + 4, 4, "tlplog1", "TLP Prefix Log 1",
+ pcieadm_cfgspace_print_hex },
+ { PCIE_AER_TLP_PRE_LOG + 8, 4, "tlplog2", "TLP Prefix Log 2",
+ pcieadm_cfgspace_print_hex },
+ { PCIE_AER_TLP_PRE_LOG + 12, 4, "tlplog3", "TLP Prefix Log 3",
+ pcieadm_cfgspace_print_hex },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cap_aer_bridge[] = {
+ { PCIE_AER_CAP, 4, "caphdr", "Capability Header",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
+ { PCIE_AER_UCE_STS, 4, "uestatus", "Uncorrectable Error Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ue },
+ { PCIE_AER_UCE_MASK, 4, "uemask", "Uncorrectable Error Mask",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ue },
+ { PCIE_AER_UCE_SERV, 4, "ueserv", "Uncorrectable Error Severity",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ue },
+ { PCIE_AER_CE_STS, 4, "cestatus", "Correctable Error Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ce },
+ { PCIE_AER_CE_MASK, 4, "cemask", "Correctable Error Mask",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ce },
+ { PCIE_AER_CTL, 4, "ctrl", "Advanced Error Capabilities and Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ctrl },
+ { PCIE_AER_HDR_LOG + 4, 4, "hl0", "Header Log 0",
+ pcieadm_cfgspace_print_hex },
+ { PCIE_AER_HDR_LOG + 8, 4, "hl1", "Header Log 1",
+ pcieadm_cfgspace_print_hex },
+ { PCIE_AER_HDR_LOG + 12, 4, "hl2", "Header Log 2",
+ pcieadm_cfgspace_print_hex },
+ { PCIE_AER_HDR_LOG + 12, 4, "hl3", "Header Log 3",
+ pcieadm_cfgspace_print_hex },
+ { PCIE_AER_CTL, 4, "rootcmd", "Root Error Command",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_rootcom },
+ { PCIE_AER_RE_STS, 4, "rootsts", "Root Error Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_rootsts },
+ { PCIE_AER_CE_SRC_ID, 4, "esi", "Error Source Identification",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_esi },
+ { PCIE_AER_SUCE_STS, 4, "secuests",
+ "Secondary Uncorrectable Error Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_secue },
+ { PCIE_AER_SUCE_MASK, 4, "secuests",
+ "Secondary Uncorrectable Error Mask",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_secue },
+ { PCIE_AER_SUCE_SERV, 4, "secuests",
+ "Secondary Uncorrectable Error Severity",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_secue },
+ { PCIE_AER_SCTL, 4, "secctrl",
+ "Secondary Error Capabilityes and Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_secctl },
+ { PCIE_AER_SHDR_LOG, 4, "shl0", "Secondary Header Log 0",
+ pcieadm_cfgspace_print_hex },
+ { PCIE_AER_SHDR_LOG + 4, 4, "shl1", "Secondary Header Log 1",
+ pcieadm_cfgspace_print_hex },
+ { PCIE_AER_SHDR_LOG + 8, 4, "shl1", "Secondary Header Log 2",
+ pcieadm_cfgspace_print_hex },
+ { PCIE_AER_SHDR_LOG + 12, 4, "shl1", "Secondary Header Log 3",
+ pcieadm_cfgspace_print_hex },
+ { -1, -1, NULL }
+};
+
+/*
+ * Secondary PCI Express Extended Capability
+ */
+static pcieadm_regdef_t pcieadm_regdef_pcie2_linkctl3[] = {
+ { 0, 0, "peq", "Perform Equalization", PRDV_HEX },
+ { 1, 1, "leqrie", "Link Equalization Request Interrupt Enable",
+ PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 9, 15, "elskpos", "Enable Lower SKP OS Generation Vector",
+ PRDV_BITFIELD,
+ .prd_val = { .prdv_strval = { "2.5 GT/s", "5.0 GT/s", "8.0 GT/s",
+ "16.0 GT/s", "32.0 GT/s" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_pcie2_linkeq[] = {
+ { 0, 3, "dstxpre", "Downstream Port 8.0 GT/s Transmitter Preset",
+ PRDV_HEX },
+ { 4, 6, "dstxhint", "Downstream Port 8.0 GT/s Receiver Hint",
+ PRDV_HEX },
+ { 8, 11, "ustxpre", "Upstream Port 8.0 GT/s Transmitter Preset",
+ PRDV_HEX },
+ { 12, 14, "ustxhint", "Upstream Port 8.0 GT/s Receiver Hint",
+ PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static void
+pcieadm_cfgspace_print_laneq(pcieadm_cfgspace_walk_t *walkp,
+ pcieadm_cfgspace_print_t *print, void *arg)
+{
+ if (walkp->pcw_nlanes == 0) {
+ warnx("failed to capture lane count, but somehow have "
+ "secondary PCIe cap");
+ return;
+ }
+
+ for (uint_t i = 0; i < walkp->pcw_nlanes; i++) {
+ char eqshort[32], eqhuman[128];
+ pcieadm_cfgspace_print_t p;
+
+ (void) snprintf(eqshort, sizeof (eqshort), "lane%u", i);
+ (void) snprintf(eqhuman, sizeof (eqhuman), "Lane %u EQ Control",
+ i);
+ p.pcp_off = print->pcp_off + i * 2;
+ p.pcp_len = 2;
+ p.pcp_short = eqshort;
+ p.pcp_human = eqhuman;
+ p.pcp_print = pcieadm_cfgspace_print_regdef;
+ p.pcp_arg = pcieadm_regdef_pcie2_linkeq;
+
+ p.pcp_print(walkp, &p, p.pcp_arg);
+ }
+}
+
+static pcieadm_cfgspace_print_t pcieadm_cap_pcie2[] = {
+ { 0x0, 4, "caphdr", "Capability Header",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
+ { 0x4, 4, "linkctl3", "Link Control 3",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie2_linkctl3 },
+ { 0x8, 4, "laneerr", "Lane Error Status", pcieadm_cfgspace_print_hex },
+ { 0xc, 2, "eqctl", "Lane Equalization Control",
+ pcieadm_cfgspace_print_laneq },
+ { -1, -1, NULL }
+};
+
+/*
+ * Access Control Services
+ */
+static pcieadm_regdef_t pcieadm_regdef_acs_cap[] = {
+ { 0, 0, "srcvd", "ACS Source Validation", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 1, 1, "tranblk", "ACS Transaction Blocking", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 2, 2, "p2prr", "ACS P2P Request Redirect", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 3, 3, "p2pcr", "ACS P2P Completion Redirect", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 4, 4, "upfwd", "ACS Upstream Forwarding", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 5, 5, "p2pegctl", "ACS P2P Egress Control", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 6, 6, "dtp2p", "ACS Direct Translated P2P", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 7, 7, "enhcap", "ACS Enhanced Capability", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 8, 15, "ecvsz", "Egress Control Vector Size", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_acs_ctl[] = {
+ { 0, 0, "srcvd", "ACS Source Validation", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 1, 1, "tranblk", "ACS Transaction Blocking", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 2, 2, "p2prr", "ACS P2P Request Redirect", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 3, 3, "p2pcr", "ACS P2P Completion Redirect", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 4, 4, "upfwd", "ACS Upstream Forwarding", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 5, 5, "p2pegctl", "ACS P2P Egress Control", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 6, 6, "dtp2p", "ACS Direct Translated P2P", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 7, 7, "iorb", "ACS I/O Request Blocking", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 8, 9, "dspmta", "ACS DSP Memory Target Access Control", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "Direct Request access",
+ "Request blocking", "Request redirect" } } },
+ { 10, 11, "uspmta", "ACS USP Memory Target Access Control", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "Direct Request access",
+ "Request blocking", "Request redirect" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cap_acs[] = {
+ { 0x0, 4, "caphdr", "Capability Header",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
+ { 0x4, 2, "cap", "ACS Capability",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_acs_cap },
+ { 0x6, 2, "ctl", "ACS Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_acs_ctl },
+ { 0x8, 4, "ecv", "Egress Control Vector", pcieadm_cfgspace_print_ecv },
+ { -1, -1, NULL }
+};
+
+/*
+ * L1 PM Substates
+ */
+static pcieadm_regdef_t pcieadm_regdef_l1pm_cap[] = {
+ { 0, 0, "pcil1.2", "PCI-PM L1.2", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 1, 1, "pcil1.1", "PCI-PM L1.1", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 2, 2, "aspml1.2", "ASPM L1.2", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 3, 3, "aspml1.1", "ASPM L1.1", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 4, 4, "l1pmsub", "L1 PM Substates", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 5, 5, "linkact", "Link Activation", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 8, 15, "pcmrt", "Port Common_Mode_Restore_Time", PRDV_HEX },
+ { 16, 17, "poscale", "Port T_POWER_ON Scale", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "2 us", "10 us", "100 us" } } },
+ { 19, 23, "portpo", "Port T_POWER_ON Value", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_l1pm_ctl1[] = {
+ { 0, 0, "pcil1.2", "PCI-PM L1.2", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 1, 1, "pcil1.1", "PCI-PM L1.1", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 2, 2, "aspml1.2", "ASPM L1.2", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 3, 3, "aspml1.1", "ASPM L1.1", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 4, 4, "laie", "Link Activation Interrupt Enable", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 5, 5, "lactl", "Link Activation Control", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 8, 15, "cmrt", "Common_Mode_Restore_Time", PRDV_HEX },
+ { 16, 25, "ltrl1.2", "LTR L1.2 Threshold Value", PRDV_HEX },
+ { 29, 31, "ltrl1.2s", "LTR L1.2 Threshold Scale", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "1 ns", "32 ns", "1024 ns",
+ "32,768 ns", "1,048,576 ns", "33,554,432 ns" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_l1pm_ctl2[] = {
+ { 0, 1, "poscale", "T_POWER_ON Scale", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "2 us", "10 us", "100 us" } } },
+ { 3, 7, "portpo", "T_POWER_ON Value", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_l1pm_sts[] = {
+ { 0, 0, "la", "Link Activation", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+
+static pcieadm_cfgspace_print_t pcieadm_cap_l1pm_v1[] = {
+ { 0x0, 4, "caphdr", "Capability Header",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
+ { 0x4, 4, "caps", "L1 PM Substates Capabilities",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_l1pm_cap },
+ { 0x8, 4, "ctl1", "L1 PM Substates Control 1",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_l1pm_ctl1 },
+ { 0xc, 4, "ctl1", "L1 PM Substates Control 2",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_l1pm_ctl2 },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cap_l1pm_v2[] = {
+ { 0x0, 4, "caphdr", "Capability Header",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
+ { 0x4, 4, "caps", "L1 PM Substates Capabilities",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_l1pm_cap },
+ { 0x8, 4, "ctl1", "L1 PM Substates Control 1",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_l1pm_ctl1 },
+ { 0xc, 4, "ctl1", "L1 PM Substates Control 2",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_l1pm_ctl2 },
+ { 0x10, 4, "sts", "L1 PM Substates Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_l1pm_sts },
+ { -1, -1, NULL }
+};
+
+/*
+ * Latency Tolerance Reporting (LTR)
+ */
+static pcieadm_regdef_t pcieadm_regdef_ltr[] = {
+ { 0, 9, "latval", "Latency Value", PRDV_HEX },
+ { 10, 12, "latscale", "Latency Scale", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "1 ns", "32 ns", "1024 ns",
+ "32,768 ns", "1,048,576 ns", "33,554,432 ns" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cap_ltr[] = {
+ { 0x0, 4, "caphdr", "Capability Header",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
+ { 0x4, 2, "snoop", "Max Snoop Latency",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ltr },
+ { 0x6, 2, "snoop", "Max No-Snoop Latency",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ltr },
+ { -1, -1, NULL }
+};
+
+/*
+ * Alternative Routing ID
+ */
+static pcieadm_regdef_t pcieadm_regdef_ari_cap[] = {
+ { 0, 0, "mfvcfg", "MFVC Function Groups", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 1, 1, "acsfg", "ACS Function Groups", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 8, 15, "nfunc", "Next Function Number", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_ari_ctl[] = {
+ { 0, 0, "mfvcfg", "MFVC Function Groups", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 1, 1, "acsfg", "ACS Function Groups", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 4, 6, "fgrp", "Function Group", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cap_ari[] = {
+ { 0x0, 4, "caphdr", "Capability Header",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
+ { 0x4, 2, "cap", "ARI Capability",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ari_cap },
+ { 0x6, 2, "ctl", "ARI Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ari_ctl },
+ { -1, -1, NULL }
+};
+
+/*
+ * PASID
+ */
+static pcieadm_regdef_t pcieadm_regdef_pasid_cap[] = {
+ { 1, 1, "exec", "Execution Permission", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 2, 2, "priv", "Privileged Mode", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 8, 12, "width", "Max PASID Width", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_pasid_ctl[] = {
+ { 0, 0, "pasid", "PASID", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 1, 1, "exec", "Execution Permission", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 2, 2, "priv", "Privileged Mode", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { -1, -1, NULL }
+};
+
+
+static pcieadm_cfgspace_print_t pcieadm_cap_pasid[] = {
+ { 0x0, 4, "caphdr", "Capability Header",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
+ { 0x4, 2, "cap", "PASID Capability",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pasid_cap },
+ { 0x6, 2, "ctl", "PASID Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pasid_ctl },
+ { -1, -1, NULL }
+};
+
+/*
+ * "Advanced Features"
+ */
+static pcieadm_regdef_t pcieadm_regdef_af_cap[] = {
+ { 0, 0, "tp", "Transactions Pending", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 1, 1, "flr", "Function Level Reset", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_af_ctl[] = {
+ { 0, 0, "flr", "Function Level Reset", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_af_sts[] = {
+ { 0, 0, "tp", "Transactions Pending", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "none pending", "pending" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cap_af[] = {
+ { 0x2, 2, "cap", "AF Capabilities",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_af_cap },
+ { 0x4, 1, "ctl", "AF Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_af_ctl },
+ { 0x5, 1, "sts", "AF Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_af_sts },
+ { -1, -1, NULL }
+};
+
+/*
+ * Multicast
+ */
+static pcieadm_regdef_t pcieadm_regdef_mcast_cap[] = {
+ { 0, 5, "maxgrp", "Max Group", PRDV_HEX,
+ .prd_val = { .prdv_hex = { 0, 1 } } },
+ { 8, 13, "winsize", "Window Size (raw)", PRDV_HEX },
+ { 15, 15, "ecrc", "ECRC Regeneration", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_mcast_ctl[] = {
+ { 0, 5, "numgrp", "Number of Groups", PRDV_HEX,
+ .prd_val = { .prdv_hex = { 0, 1 } } },
+ { 15, 15, "enable", "Enable", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_mcast_base[] = {
+ { 0, 5, "index", "Multicast Index Position", PRDV_HEX },
+ { 12, 63, "addr", "Base Address", PRDV_HEX,
+ .prd_val = { .prdv_hex = { 12 } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_mcast_overlay[] = {
+ { 0, 5, "size", "Overlay Size (raw)", PRDV_HEX },
+ { 6, 63, "addr", "Overlay Base Address", PRDV_HEX,
+ .prd_val = { .prdv_hex = { 6 } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cap_mcast[] = {
+ { 0x0, 4, "caphdr", "Capability Header",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
+ { 0x4, 2, "cap", "Multicast Capability",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_mcast_cap },
+ { 0x6, 2, "ctl", "Multicast Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_mcast_ctl },
+ { 0x8, 8, "base", "Multicast Base Address",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_mcast_base },
+ { 0x10, 8, "rx", "Multicast Receive", pcieadm_cfgspace_print_hex },
+ { 0x18, 8, "block", "Multicast Block All", pcieadm_cfgspace_print_hex },
+ { 0x20, 8, "blockun", "Multicast Block Untranslated",
+ pcieadm_cfgspace_print_hex },
+ { 0x28, 8, "overlay", "Multicast Overlay BAR",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_mcast_overlay },
+ { -1, -1, NULL }
+};
+
+/*
+ * Various vendor extensions
+ */
+static pcieadm_regdef_t pcieadm_regdef_vsec[] = {
+ { 0, 15, "id", "ID", PRDV_HEX },
+ { 16, 19, "rev", "Revision", PRDV_HEX },
+ { 20, 31, "len", "Length", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cap_vs[] = {
+ { 0x2, 2, "length", "Length", pcieadm_cfgspace_print_hex },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cap_vsec[] = {
+ { 0x0, 4, "caphdr", "Capability Header",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
+ { 0x4, 4, "header", "Vendor-Specific Header",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_vsec },
+ { -1, -1, NULL }
+};
+
+/*
+ * Data Link Feature
+ */
+static pcieadm_regdef_t pcieadm_regdef_dlf_cap[] = {
+ { 0, 0, "lsfc", "Local Scaled Flow Control", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 31, 31, "dlex", "Data Link Exchange", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_dlf_sts[] = {
+ { 0, 0, "rsfc", "Remote Scaled Flow Control", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 31, 31, "valid", "Remote Data Link Feature Valid", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "invalid", "valid" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cap_dlf[] = {
+ { 0x0, 4, "caphdr", "Capability Header",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
+ { 0x4, 4, "cap", "Data Link Feature Capabilities",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_dlf_cap },
+ { 0x8, 4, "sts", "Data Link Feature Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_dlf_sts },
+ { -1, -1, NULL }
+};
+
+/*
+ * 16.0 GT/s cap
+ */
+static pcieadm_regdef_t pcieadm_regdef_16g_cap[] = {
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_16g_ctl[] = {
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_16g_sts[] = {
+ { 0, 0, "eqcomp", "Equalization 16.0 GT/s Complete", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "incomplete", "complete" } } },
+ { 1, 1, "eqp1", "Equalization 16.0 GT/s Phase 1", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "incomplete", "complete" } } },
+ { 2, 2, "eqp2", "Equalization 16.0 GT/s Phase 2", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "incomplete", "complete" } } },
+ { 3, 3, "eqp3", "Equalization 16.0 GT/s Phase 3", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "incomplete", "complete" } } },
+ { 4, 4, "req", "Link Equalization Request 16.0 GT/s", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_16g_eq[] = {
+ { 0, 3, "dstxpre", "Downstream Port 16.0 GT/s Transmitter Preset",
+ PRDV_HEX },
+ { 4, 7, "ustxpre", "Upstream Port 16.0 GT/s Transmitter Preset",
+ PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static void
+pcieadm_cfgspace_print_16geq(pcieadm_cfgspace_walk_t *walkp,
+ pcieadm_cfgspace_print_t *print, void *arg)
+{
+ if (walkp->pcw_nlanes == 0) {
+ warnx("failed to capture lane count, but somehow have "
+ "secondary PCIe cap");
+ return;
+ }
+
+ for (uint_t i = 0; i < walkp->pcw_nlanes; i++) {
+ char eqshort[32], eqhuman[128];
+ pcieadm_cfgspace_print_t p;
+
+ (void) snprintf(eqshort, sizeof (eqshort), "lane%u", i);
+ (void) snprintf(eqhuman, sizeof (eqhuman), "Lane %u EQ Control",
+ i);
+ p.pcp_off = print->pcp_off + i * 1;
+ p.pcp_len = 1;
+ p.pcp_short = eqshort;
+ p.pcp_human = eqhuman;
+ p.pcp_print = pcieadm_cfgspace_print_regdef;
+ p.pcp_arg = pcieadm_regdef_16g_eq;
+
+ p.pcp_print(walkp, &p, p.pcp_arg);
+ }
+}
+
+static pcieadm_cfgspace_print_t pcieadm_cap_16g[] = {
+ { 0x0, 4, "caphdr", "Capability Header",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
+ { 0x4, 4, "cap", "16.0 GT/s Capabilities",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_16g_cap },
+ { 0x8, 4, "ctl", "16.0 GT/s Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_16g_ctl },
+ { 0xc, 4, "sts", "16.0 GT/s Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_16g_sts },
+ { 0x10, 4, "ldpmis", "16.0 GT/s Local Data Parity Mismatch",
+ pcieadm_cfgspace_print_hex },
+ { 0x14, 4, "frpmis", "16.0 GT/s First Retimer Data Parity Mismatch",
+ pcieadm_cfgspace_print_hex },
+ { 0x18, 4, "srpmis", "16.0 GT/s Second Retimer Data Parity Mismatch",
+ pcieadm_cfgspace_print_hex },
+ { 0x1c, 4, "rsvd", "16.0 GT/s Second Retimer Data Parity Mismatch",
+ pcieadm_cfgspace_print_hex },
+ { 0x20, 1, "eqctl", "16.0 GT/s EQ Control",
+ pcieadm_cfgspace_print_16geq },
+ { -1, -1, NULL }
+};
+
+/*
+ * Receiver Margining
+ */
+static pcieadm_regdef_t pcieadm_regdef_margin_cap[] = {
+ { 0, 0, "sw", "Margining uses Driver Software", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_margin_sts[] = {
+ { 0, 0, "ready", "Margining Ready", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 1, 1, "sw", "Margining Software Ready", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_margin_lane[] = {
+ { 0, 2, "rxno", "Receiver Number", PRDV_HEX },
+ { 3, 5, "type", "Margin Type", PRDV_HEX },
+ { 6, 6, "model", "Usage Model", PRDV_HEX },
+ { 8, 15, "payload", "Margin Payload", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static void
+pcieadm_cfgspace_print_margin(pcieadm_cfgspace_walk_t *walkp,
+ pcieadm_cfgspace_print_t *print, void *arg)
+{
+ if (walkp->pcw_nlanes == 0) {
+ warnx("failed to capture lane count, but somehow have "
+ "lane margining capability");
+ return;
+ }
+
+ for (uint_t i = 0; i < walkp->pcw_nlanes; i++) {
+ char mshort[32], mhuman[128];
+ pcieadm_cfgspace_print_t p;
+
+ (void) snprintf(mshort, sizeof (mshort), "lane%uctl", i);
+ (void) snprintf(mhuman, sizeof (mhuman), "Lane %u Margining "
+ "Control", i);
+ p.pcp_off = print->pcp_off + i * 4;
+ p.pcp_len = 2;
+ p.pcp_short = mshort;
+ p.pcp_human = mhuman;
+ p.pcp_print = pcieadm_cfgspace_print_regdef;
+ p.pcp_arg = pcieadm_regdef_margin_lane;
+
+ p.pcp_print(walkp, &p, p.pcp_arg);
+
+ (void) snprintf(mshort, sizeof (mshort), "lane%usts", i);
+ (void) snprintf(mhuman, sizeof (mhuman), "Lane %u Margining "
+ "Status", i);
+ p.pcp_off = print->pcp_off + 2 + i * 4;
+ p.pcp_len = 2;
+ p.pcp_short = mshort;
+ p.pcp_human = mhuman;
+ p.pcp_print = pcieadm_cfgspace_print_regdef;
+ p.pcp_arg = pcieadm_regdef_margin_lane;
+
+ p.pcp_print(walkp, &p, p.pcp_arg);
+ }
+}
+
+static pcieadm_cfgspace_print_t pcieadm_cap_margin[] = {
+ { 0x0, 4, "caphdr", "Capability Header",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
+ { 0x4, 2, "cap", "Margining Port Capabilities",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_margin_cap },
+ { 0x6, 2, "sts", "Margining Port Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_margin_sts },
+ { 0x8, 4, "lane", "Margining Lane", pcieadm_cfgspace_print_margin },
+ { -1, -1, NULL }
+};
+
+/*
+ * Serial Number Capability
+ */
+static void
+pcieadm_cfgspace_print_sn(pcieadm_cfgspace_walk_t *walkp,
+ pcieadm_cfgspace_print_t *print, void *arg)
+{
+ char sn[64];
+ uint16_t off = walkp->pcw_capoff + print->pcp_off;
+
+ (void) snprintf(sn, sizeof (sn),
+ "%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x",
+ walkp->pcw_data->pcb_u8[off + 7], walkp->pcw_data->pcb_u8[off + 6],
+ walkp->pcw_data->pcb_u8[off + 5], walkp->pcw_data->pcb_u8[off + 4],
+ walkp->pcw_data->pcb_u8[off + 3], walkp->pcw_data->pcb_u8[off + 2],
+ walkp->pcw_data->pcb_u8[off + 1], walkp->pcw_data->pcb_u8[off]);
+
+ pcieadm_cfgspace_puts(walkp, print, sn);
+}
+
+static pcieadm_cfgspace_print_t pcieadm_cap_sn[] = {
+ { 0x0, 4, "caphdr", "Capability Header",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
+ { 0x4, 8, "sn", "Serial Number", pcieadm_cfgspace_print_sn },
+ { -1, -1, NULL }
+};
+
+/*
+ * TLP Processing Hints (TPH)
+ */
+static pcieadm_regdef_t pcieadm_regdef_tph_cap[] = {
+ { 0, 0, "nost", "No ST Mode", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 1, 1, "ivec", "Interrupt Vector Mode", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 2, 2, "dev", "Device Specific Mode", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 8, 8, "exttph", "Extended TPH Requester", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 9, 10, "loc", "ST Table Location", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "Not Present",
+ "In Capability Structure", "MSI-X" } } },
+ { 16, 26, "size", "ST Table Size", PRDV_HEX, { .prdv_hex = { 0, 1 } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_tph_ctl[] = {
+ { 0, 2, "mode", "ST Mode Select", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "No ST", "Interrupt Vector",
+ "Device Specific" } } },
+ { 8, 9, "en", "TPH Requester", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "Not Permitted", "TPH", NULL,
+ "TPH and Extended TPH" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_tph_st[] = {
+ { 0, 7, "low", "ST Lower", PRDV_HEX },
+ { 8, 15, "up", "ST Upper", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+/*
+ * The TPH ST table is only conditionally present in the capability. So we need
+ * to read the TPH capability register and then check if the table location and
+ * size are set here.
+ */
+static void
+pcieadm_cfgspace_print_tphst(pcieadm_cfgspace_walk_t *walkp,
+ pcieadm_cfgspace_print_t *print, void *arg)
+{
+ uint_t nents;
+ uint32_t tphcap = walkp->pcw_data->pcb_u32[(walkp->pcw_capoff + 4) / 4];
+
+ if (BITX(tphcap, 10, 9) != 1) {
+ return;
+ }
+
+ nents = BITX(tphcap, 26, 16) + 1;
+ for (uint_t i = 0; i < nents; i++) {
+ char tshort[32], thuman[128];
+ pcieadm_cfgspace_print_t p;
+
+ (void) snprintf(tshort, sizeof (tshort), "st%u", i);
+ (void) snprintf(thuman, sizeof (thuman), "ST Table %u",
+ i);
+ p.pcp_off = print->pcp_off + i * 2;
+ p.pcp_len = 2;
+ p.pcp_short = tshort;
+ p.pcp_human = thuman;
+ p.pcp_print = pcieadm_cfgspace_print_regdef;
+ p.pcp_arg = pcieadm_regdef_tph_st;
+
+ p.pcp_print(walkp, &p, p.pcp_arg);
+ }
+}
+
+static pcieadm_cfgspace_print_t pcieadm_cap_tph[] = {
+ { 0x0, 4, "caphdr", "Capability Header",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
+ { 0x4, 4, "cap", "TPH Requester Capability",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_tph_cap },
+ { 0x8, 4, "ctl", "TPH Requester Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_tph_ctl },
+ { 0xc, 2, "table", "ST Table", pcieadm_cfgspace_print_tphst },
+ { -1, -1, NULL }
+};
+
+/*
+ * SR-IOV
+ */
+static pcieadm_regdef_t pcieadm_regdef_sriov_cap[] = {
+ { 0, 0, "migration", "Migration", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 1, 1, "ari", "ARI Capable Hierarchy Preserved", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unpreserved", "preserved" } } },
+ { 2, 2, "vf10b", "VF 10-bit Tag Requester", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unpreserved", "preserved" } } },
+ { 21, 31, "inum", "VF Migration Interrupt Message Number", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_sriov_ctl[] = {
+ { 0, 0, "vf", "VF", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 1, 1, "vfm", "VF Migration", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 2, 2, "vfmi", "VF Migration Interrupt", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 3, 3, "ari", "ARI Capable Hierarchy", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 4, 4, "vf10b", "VF 10-bit Tag Requester", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_sriov_sts[] = {
+ { 0, 0, "vfm", "VF Migration", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "none", "requested" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_sriov_pgsup[] = {
+ { 0, 31, "pgsz", "Supported Page Sizes", PRDV_BITFIELD,
+ .prd_val = { .prdv_strval = { "4 KB", "8 KB", "16 KB", "32 KB",
+ "64 KB", "128 KB", "256 KB", "512 KB", "1 MB", "2 MB", "4 MB",
+ "8 MB", "16 MB", "32 MB", "64 MB", "128 MB", "256 MB", "512 MB",
+ "1 GB", "2 GB", "4 GB", "8 GB", "16 GB", "32 GB", "64 GB",
+ "128 GB", "256 GB", "512 GB", "1 TB", "2 TB", "4 TB", "8 TB" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_sriov_pgen[] = {
+ { 0, 31, "pgsz", "System Page Sizes", PRDV_BITFIELD,
+ .prd_val = { .prdv_strval = { "4 KB", "8 KB", "16 KB", "32 KB",
+ "64 KB", "128 KB", "256 KB", "512 KB", "1 MB", "2 MB", "4 MB",
+ "8 MB", "16 MB", "32 MB", "64 MB", "128 MB", "256 MB", "512 MB",
+ "1 GB", "2 GB", "4 GB", "8 GB", "16 GB", "32 GB", "64 GB",
+ "128 GB", "256 GB", "512 GB", "1 TB", "2 TB", "4 TB", "8 TB" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_sriov_mig[] = {
+ { 0, 2, "bir", "VF Migration State BIR", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "BAR 0", "BAR 1", "BAR 2", "BAR 3",
+ "BAR 4", "BAR 5" } } },
+ { 3, 31, "offset", "VF Migration State Offset", PRDV_HEX,
+ .prd_val = { .prdv_hex = { 3 } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cap_sriov[] = {
+ { 0x0, 4, "caphdr", "Capability Header",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
+ { 0x4, 4, "cap", "SR-IOV Capabilities",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_sriov_cap },
+ { 0x8, 2, "ctl", "SR-IOV Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_sriov_ctl },
+ { 0xa, 2, "sts", "SR-IOV Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_sriov_sts },
+ { 0xc, 2, "initvfs", "Initial VFs", pcieadm_cfgspace_print_hex },
+ { 0xe, 2, "totvfs", "Total VFs", pcieadm_cfgspace_print_hex },
+ { 0x10, 2, "numvfs", "Number VFs", pcieadm_cfgspace_print_hex },
+ { 0x12, 1, "dep", "Function Dependency Link",
+ pcieadm_cfgspace_print_hex },
+ { 0x14, 2, "offset", "First VF Offset", pcieadm_cfgspace_print_hex },
+ { 0x16, 2, "stride", "VF Stride", pcieadm_cfgspace_print_hex },
+ { 0x1a, 2, "devid", "VF Device ID", pcieadm_cfgspace_print_hex },
+ { 0x1c, 4, "pgsz", "Supported Page Sizes",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_sriov_pgsup },
+ { 0x20, 4, "pgsz", "System Page Sizes",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_sriov_pgen },
+ { 0x24, 24, "vfbar", "Virtual Base Address Register",
+ pcieadm_cfgspace_print_bars },
+ { 0x3c, 4, "migration", "VF Migration State Array",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_sriov_mig },
+ { -1, -1, NULL }
+};
+
+/*
+ * PCI-X
+ */
+static pcieadm_regdef_t pcieadm_regdef_pcix_dev_ctl[] = {
+ { 0, 0, "dper", "Data Parity Error Recovery", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 1, 1, "ro", "Relaxed Ordering", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 2, 3, "maxread", "Maximum Memory Read Byte Count", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "512 bytes", "1024 bytes",
+ "2048 byes", "4096 bytes" } } },
+ { 4, 6, "maxsplit", "Maximum Outstanding Split Transactions",
+ PRDV_STRVAL, .prd_val = { .prdv_strval = { "1", "2", "3", "4", "8",
+ "12", "16", "32" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_pcix_dev_sts[] = {
+ { 0, 2, "func", "Function Number", PRDV_HEX },
+ { 3, 7, "dev", "Device Number", PRDV_HEX },
+ { 8, 15, "bus", "Bus Number", PRDV_HEX },
+ { 16, 16, "64bit", "64-bit Device", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported (32-bit)",
+ "supported" } } },
+ { 17, 17, "133mhz", "133 MHz Capable", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported (66 MHz)",
+ "supported" } } },
+ { 18, 18, "spcodis", "Split Completion Discarded", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 19, 19, "unspco", "Unexpected Split Completion", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 20, 20, "complex", "Device Complexity", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "simple", "bridge" } } },
+ { 21, 22, "maxread", "Designed Maximum Memory Read Byte Count",
+ PRDV_STRVAL, .prd_val = { .prdv_strval = { "512 bytes",
+ "1024 bytes", "2048 byes", "4096 bytes" } } },
+ { 23, 25, "maxsplit", "Designed Maximum Outstanding Split Transactions",
+ PRDV_STRVAL, .prd_val = { .prdv_strval = { "1", "2", "3", "4", "8",
+ "12", "16", "32" } } },
+ { 26, 28, "maxcread", "Designed Maximum Cumulative Read Size",
+ PRDV_STRVAL, .prd_val = { .prdv_strval = { "8/1KB", "16/2KB",
+ "32/4KB", "64/8KB", "128/16KB", "256/32KB", "512/64KB",
+ "1024/128KB" } } },
+ { 29, 29, "rxspcoer", "Received Split Completion Error Message",
+ PRDV_STRVAL, .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_pcix_sec_sts[] = {
+ { 0, 0, "64bit", "64-bit Device", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported (32-bit)",
+ "supported" } } },
+ { 1, 1, "133mhz", "133 MHz Capable", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported (66 MHz)",
+ "supported" } } },
+ { 2, 2, "spcodis", "Split Completion Discarded", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 3, 3, "unspco", "Unexpected Split Completion", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 4, 4, "spcoor", "Split Completion Overrun", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 5, 5, "sprde", "Split Request Delayed", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 6, 8, "freq", "Secondary Clock Frequency", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "conventional", "66 MHz", "100 Mhz",
+ "133 MHz" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_pcix_bridge_sts[] = {
+ { 0, 2, "func", "Function Number", PRDV_HEX },
+ { 3, 7, "dev", "Device Number", PRDV_HEX },
+ { 8, 15, "bus", "Bus Number", PRDV_HEX },
+ { 16, 16, "64bit", "64-bit Device", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported (32-bit)",
+ "supported" } } },
+ { 17, 17, "133mhz", "133 MHz Capable", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported (66 MHz)",
+ "supported" } } },
+ { 18, 18, "spcodis", "Split Completion Discarded", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 19, 19, "unspco", "Unexpected Split Completion", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 20, 20, "spcoor", "Split Completion Overrun", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 21, 21, "sprde", "Split Request Delayed", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_pcix_bridge_split[] = {
+ { 0, 15, "cap", "Split Transaction Capacity", PRDV_HEX },
+ { 16, 31, "limit", "Split Transaction Commitment Limit", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cap_pcix_dev[] = {
+ { 0x2, 2, "ctl", "PCI-X Command",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcix_dev_ctl },
+ { 0x4, 4, "sts", "PCI-X Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcix_dev_sts },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cap_pcix_bridge[] = {
+ { 0x2, 2, "secsts", "PCI-X Secondary Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcix_sec_sts },
+ { 0x4, 4, "sts", "PCI-X Bridge Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcix_bridge_sts },
+ { 0x8, 4, "ussplit", "Upstream Split Transaction",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcix_bridge_split },
+ { 0x8, 4, "dssplit", "Downstream Split Transaction",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcix_bridge_split },
+ { -1, -1, NULL }
+};
+
+/*
+ * Dynamic Power Allocation
+ */
+static pcieadm_regdef_t pcieadm_regdef_dpa_cap[] = {
+ { 0, 4, "substates", "Substate Max", PRDV_HEX,
+ { .prdv_hex = { 0, 1 } } },
+ { 8, 9, "tlu", "Transition Latency Unit", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "1 ms", "10 ms", "100 ms" } } },
+ { 12, 13, "pas", "Power Allocation Scale", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "10.0x", "1.0x", "0.1x",
+ "0.01x" } } },
+ { 16, 23, "tlv0", "Transition Latency Value 0", PRDV_HEX },
+ { 24, 31, "tlv0", "Transition Latency Value 1", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_dpa_sts[] = {
+ { 0, 4, "substate", "Substate Status", PRDV_HEX },
+ { 8, 8, "ctlen", "Substate Control Enabled", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_dpa_ctl[] = {
+ { 0, 4, "substate", "Substate Control", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cap_dpa[] = {
+ { 0x0, 4, "caphdr", "Capability Header",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
+ { 0x4, 4, "cap", "DPA Capability",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_dpa_cap },
+ { 0x8, 4, "lat", "DPA Latency Indicator", pcieadm_cfgspace_print_hex },
+ { 0xc, 2, "sts", "DPA Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_dpa_sts },
+ { 0xe, 2, "sts", "DPA Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_dpa_ctl },
+ { 0x10, 1, "paa", "DPA Power Allocation Array",
+ pcieadm_cfgspace_print_dpa_paa },
+ { -1, -1, NULL }
+};
+
+/*
+ * Power Budgeting
+ */
+static pcieadm_regdef_t pcieadm_regdef_powbudg_data[] = {
+ { 0, 7, "base", "Base Power", PRDV_HEX },
+ { 8, 9, "scale", "Data Scale", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "1.0x", "0.1x", "0.01x",
+ "0.001x" } } },
+ { 10, 12, "pmsub", "PM Substate", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "Default", "Device Specific",
+ "Device Specific", "Device Specific", "Device Specific",
+ "Device Specific", "Device Specific", "Device Specific" } } },
+ { 13, 14, "pmstate", "PM State", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "D0", "D1", "D2", "D3" } } },
+ { 15, 17, "type", "Type", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "PME Aux", "Axiliary", "Idle",
+ "Sustained", "Sustained - EPRS", "Maximum - EPRS", NULL,
+ "Maximum" } } },
+ { 18, 20, "rail", "Power Rail", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "Power (12V)", "Power (3.3V)",
+ "Power (1.5V or 1.8V)", NULL, NULL, NULL, NULL, "Thermal" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_powbudg_cap[] = {
+ { 0, 0, "sa", "System Allocated", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { -1, -1, NULL }
+};
+
+
+static pcieadm_cfgspace_print_t pcieadm_cap_powbudg[] = {
+ { 0x0, 4, "caphdr", "Capability Header",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
+ { 0x4, 1, "sel", "Data Select", pcieadm_cfgspace_print_hex },
+ { 0x8, 4, "data", "Data Regiser", pcieadm_cfgspace_print_regdef,
+ pcieadm_regdef_powbudg_data },
+ { 0xc, 0x1, "cap", "Power Budget Capability",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_powbudg_cap },
+ { -1, -1, NULL }
+};
+
+/*
+ * Precision Time Management
+ */
+static pcieadm_regdef_t pcieadm_regdef_ptm_cap[] = {
+ { 0, 0, "req", "PTM Requester", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 1, 1, "resp", "PTM Responder", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 2, 2, "root", "PTM Root", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 3, 3, "eptm", "ePTM", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 8, 15, "gran", "Local Clock Granularity", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_ptm_ctl[] = {
+ { 0, 0, "en", "PTM Enable", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 1, 1, "root", "Root Select", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 8, 15, "gran", "Effective Granularity", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cap_info_ptm[] = {
+ { 0x0, 4, "caphdr", "Capability Header",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
+ { 0x4, 4, "cap", "PTM Capability",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ptm_cap },
+ { 0x8, 4, "cap", "PTM Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ptm_ctl },
+ { -1, -1, NULL }
+};
+
+/*
+ * Address Translation Services (ATS)
+ */
+static pcieadm_regdef_t pcieadm_regdef_ats_cap[] = {
+ { 0, 4, "invqd", "Invalidate Queue Depth", PRDV_HEX },
+ { 5, 5, "pgalign", "Page Aligned Request", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "not required", "required" } } },
+ { 6, 6, "glbinv", "Global Invalidate", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 7, 7, "relo", "Relaxed Ordering", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_ats_ctl[] = {
+ { 0, 4, "stu", "Smallest Translation Unit", PRDV_HEX },
+ { 15, 15, "en", "Enable", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cap_ats[] = {
+ { 0x0, 4, "caphdr", "Capability Header",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
+ { 0x4, 2, "cap", "ATS Capability",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ats_cap },
+ { 0x6, 2, "cap", "ATS Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ats_ctl },
+ { -1, -1, NULL }
+};
+
+/*
+ * Page Request
+ */
+static pcieadm_regdef_t pcieadm_regdef_pgreq_ctl[] = {
+ { 0, 0, "en", "Enable", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 1, 1, "reset", "Reset", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_pgreq_sts[] = {
+ { 0, 0, "rf", "Response Failure", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 1, 1, "uprgi", "Unexpected Page Request Group Index", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 8, 8, "stopped", "Stopped", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 15, 15, "prgrpreq", "PRG Response PASID", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "not required", "required" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cap_pgreq[] = {
+ { 0x0, 4, "caphdr", "Capability Header",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
+ { 0x4, 2, "ctl", "Page Request Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pgreq_ctl },
+ { 0x6, 2, "ctl", "Page Request Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pgreq_sts },
+ { 0x8, 4, "cap", "Outstanding Page Request Capacity",
+ pcieadm_cfgspace_print_hex },
+ { 0xc, 4, "alloc", "Outstanding Page Request Allocation",
+ pcieadm_cfgspace_print_hex },
+ { -1, -1, NULL }
+};
+
+/*
+ * NULL Capability
+ */
+static pcieadm_cfgspace_print_t pcieadm_cap_null[] = {
+ { 0x0, 4, "caphdr", "Capability Header",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
+ { -1, -1, NULL }
+};
+
+/*
+ * Downstream Port Containment
+ */
+static pcieadm_regdef_t pcieadm_regdef_dpc_cap[] = {
+ { 0, 4, "inum", "DPC Interrupt Message Number", PRDV_HEX },
+ { 5, 5, "rpext", "Root Port Extensions", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 6, 6, "ptlpeb", "Poisoned TLP Egress Blocking", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 7, 7, "swtrig", "Software Triggering", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 8, 11, "logsz", "RP PIO Log Size", PRDV_HEX },
+ { 12, 12, "errcorr", "DL_Active ERR_COR Signaling", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_dpc_ctl[] = {
+ { 0, 1, "trigger", "DPC Trigger", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled, fatal",
+ "enabled, non-fatal" } } },
+ { 2, 2, "comp", "Completion Control", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "Completer Abort",
+ "Unsupported Request" } } },
+ { 3, 3, "intr", "Interrupt",
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 4, 4, "errcor", "ERR_COR",
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 5, 5, "ptlpeb", "Poisoned TLP Egress Blocking", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 6, 6, "swtrig", "Software Trigger", PRDV_HEX },
+ { 7, 7, "corerr", "DL_Active ERR_COR",
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 8, 8, "sigsfw", "SIG_SFW",
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_dpc_sts[] = {
+ { 0, 0, "trigger", "Trigger Status", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "not triggered", "triggered" } } },
+ { 1, 2, "reason", "Trigger Reason", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unmasked uncorrectable",
+ "ERR_NONFATAL received", "ERR_FATAL received",
+ "see extension" } } },
+ { 3, 3, "istatus", "Interrupt Status", PRDV_HEX },
+ { 4, 4, "rpbusy", "RP Busy", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "no", "yes" } } },
+ { 5, 6, "extreason", "Trigger Reason Extension", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "RP PIO", "Software Trigger" } } },
+ { 8, 12, "feptr", "RP PIO, First Error Pointer", PRDV_HEX },
+ { 13, 13, "sigsfw", "SIG_SFW Status", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_dpc_rppio_bits[] = {
+ { 0, 0, "cfgur", "Configuration Request UR Completion", PRDV_HEX },
+ { 1, 1, "cfgca", "Configuration Request CA Completion", PRDV_HEX },
+ { 2, 2, "cfgcto", "Configuration Request Completion Timeout",
+ PRDV_HEX },
+ { 8, 8, "iour", "I/O UR Completion", PRDV_HEX },
+ { 9, 9, "ioca", "I/O CA Completion", PRDV_HEX },
+ { 10, 10, "iocto", "I/O Completion Timeout", PRDV_HEX },
+ { 8, 8, "memur", "Memory UR Completion", PRDV_HEX },
+ { 9, 9, "memca", "Memory CA Completion", PRDV_HEX },
+ { 10, 10, "memcto", "Memory Completion Timeout", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static void
+pcieadm_cfgspace_print_dpc_rppio(pcieadm_cfgspace_walk_t *walkp,
+ pcieadm_cfgspace_print_t *print, void *arg)
+{
+ uint32_t cap = walkp->pcw_data->pcb_u32[(walkp->pcw_capoff + 4) / 4];
+
+ if (BITX(cap, 5, 5) == 0) {
+ return;
+ }
+
+ pcieadm_cfgspace_print_regdef(walkp, print, arg);
+}
+
+static void
+pcieadm_cfgspace_print_dpc_piohead(pcieadm_cfgspace_walk_t *walkp,
+ pcieadm_cfgspace_print_t *print, void *arg)
+{
+ uint32_t cap = walkp->pcw_data->pcb_u32[(walkp->pcw_capoff + 4) / 4];
+ uint32_t nwords = BITX(cap, 11, 8);
+
+ if (BITX(cap, 5, 5) == 0 || nwords < 4) {
+ return;
+ }
+
+ pcieadm_cfgspace_print_hex(walkp, print, NULL);
+}
+
+static void
+pcieadm_cfgspace_print_dpc_impspec(pcieadm_cfgspace_walk_t *walkp,
+ pcieadm_cfgspace_print_t *print, void *arg)
+{
+ uint32_t cap = walkp->pcw_data->pcb_u32[(walkp->pcw_capoff + 4) / 4];
+ uint32_t nwords = BITX(cap, 11, 8);
+
+ if (BITX(cap, 5, 5) == 0 || nwords < 5) {
+ return;
+ }
+
+ pcieadm_cfgspace_print_hex(walkp, print, NULL);
+}
+
+static void
+pcieadm_cfgspace_print_dpc_tlplog(pcieadm_cfgspace_walk_t *walkp,
+ pcieadm_cfgspace_print_t *print, void *arg)
+{
+ uint32_t cap = walkp->pcw_data->pcb_u32[(walkp->pcw_capoff + 4) / 4];
+ int32_t nwords = BITX(cap, 11, 8);
+
+ if (nwords == 0 || BITX(cap, 5, 5) == 0) {
+ return;
+ }
+
+ if (nwords <= 9) {
+ nwords -= 5;
+ } else {
+ nwords -= 4;
+ }
+
+ for (int32_t i = 0; i < nwords; i++) {
+ char tlpshort[32], tlphuman[128];
+ pcieadm_cfgspace_print_t p;
+
+ (void) snprintf(tlpshort, sizeof (tlpshort), "%s%u",
+ print->pcp_short, i);
+ (void) snprintf(tlphuman, sizeof (tlphuman), "%s %u",
+ print->pcp_human, i);
+ p.pcp_off = print->pcp_off + i * 4;
+ p.pcp_len = 4;
+ p.pcp_short = tlpshort;
+ p.pcp_human = tlphuman;
+ p.pcp_print = pcieadm_cfgspace_print_hex;
+ p.pcp_arg = NULL;
+
+ p.pcp_print(walkp, &p, p.pcp_arg);
+ }
+}
+
+static pcieadm_cfgspace_print_t pcieadm_cap_dpc[] = {
+ { 0x0, 4, "caphdr", "Capability Header",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
+ { 0x4, 2, "cap", "DPC Capability",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_dpc_cap },
+ { 0x6, 2, "ctl", "DPC Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_dpc_ctl },
+ { 0x8, 2, "sts", "DPC Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_dpc_sts },
+ { 0xa, 2, "srcid", "DPC Error Source ID",
+ pcieadm_cfgspace_print_hex },
+ { 0x10, 4, "rppiosts", "RP PIO Status",
+ pcieadm_cfgspace_print_dpc_rppio, pcieadm_regdef_dpc_rppio_bits },
+ { 0x14, 4, "rppiomask", "RP PIO Mask ID",
+ pcieadm_cfgspace_print_dpc_rppio, pcieadm_regdef_dpc_rppio_bits },
+ { 0x14, 4, "rppiosev", "RP PIO Severity",
+ pcieadm_cfgspace_print_dpc_rppio, pcieadm_regdef_dpc_rppio_bits },
+ { 0x18, 4, "rppiose", "RP PIO SysError",
+ pcieadm_cfgspace_print_dpc_rppio, pcieadm_regdef_dpc_rppio_bits },
+ { 0x1c, 4, "rppioex", "RP PIO Exception",
+ pcieadm_cfgspace_print_dpc_rppio, pcieadm_regdef_dpc_rppio_bits },
+ { 0x20, 4, "rppiohl0", "RP PIO Header Log 0",
+ pcieadm_cfgspace_print_dpc_piohead },
+ { 0x24, 4, "rppiohl1", "RP PIO Header Log 1",
+ pcieadm_cfgspace_print_dpc_piohead },
+ { 0x28, 4, "rppiohl2", "RP PIO Header Log 2",
+ pcieadm_cfgspace_print_dpc_piohead },
+ { 0x2c, 4, "rppiohl3", "RP PIO Header Log 3",
+ pcieadm_cfgspace_print_dpc_piohead },
+ { 0x30, 4, "impspec", "RP PIO ImpSpec Log",
+ pcieadm_cfgspace_print_dpc_impspec },
+ { 0x34, 16, "tlplog", "RP PIO TLP Prefix Log",
+ pcieadm_cfgspace_print_dpc_tlplog },
+ { -1, -1, NULL }
+};
+
+/*
+ * Virtual Channel Capability
+ */
+static pcieadm_regdef_t pcieadm_regdef_vc_cap1[] = {
+ { 0, 2, "count", "Extended VC Count", PRDV_HEX },
+ { 4, 6, "lpcount", "Low Priority Extended VC Count", PRDV_HEX },
+ { 8, 9, "refclk", "Reference Clock", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "100ns" } } },
+ { 10, 11, "patsz", "Port Arbitration Table Size", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "1 bit", "2 bits", "4 bits",
+ "8 bits" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_vc_cap2[] = {
+ { 0, 7, "arbcap", "VC Arbitration Capability", PRDV_BITFIELD,
+ .prd_val = { .prdv_strval = { "hardware fixed",
+ "32 phase weighted round robin", "64 phase weighted round robin",
+ "128 phase weighted round robin" } } },
+ { 24, 31, "offset", "VC Arbitration Table Offset", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_vc_ctl[] = {
+ { 0, 0, "loadtbl", "Load VC Arbitration Table", PRDV_HEX },
+ { 1, 3, "arbtype", "VC Arbitration Select", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "hardware fixed",
+ "32 phase weighted round robin", "64 phase weighted round robin",
+ "128 phase weighted round robin" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_vc_sts[] = {
+ { 0, 0, "table", "VC Arbitration Table Status", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_vc_rsrccap[] = {
+ { 0, 7, "arbcap", "Port Arbitration Capability", PRDV_BITFIELD,
+ .prd_val = { .prdv_strval = { "hardware fixed",
+ "32 phase weighted round robin", "64 phase weighted round robin",
+ "128 phase weighted round robin",
+ "128 phase time-based weighted round robin",
+ "256 phase weighted round robin" } } },
+ { 14, 14, "aps", "Advanced Packet Switching", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 15, 15, "rstx", "Reject Snoop Transactions", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 16, 22, "nslots", "Maximum Time Slots", PRDV_HEX,
+ { .prdv_hex = { 0, 1 } } },
+ { 24, 31, "offset", "VC Arbitration Table Offset", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_vc_rsrcctl[] = {
+ { 0, 7, "tcmap", "TC/VC Map", PRDV_HEX },
+ { 16, 16, "loadtbl", "Load VC Arbitration Table", PRDV_HEX },
+ { 17, 19, "arbtype", "Port Arbitration Select", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "hardware fixed",
+ "32 phase weighted round robin", "64 phase weighted round robin",
+ "128 phase weighted round robin",
+ "128 phase time-based weighted round robin",
+ "256 phase weighted round robin" } } },
+ { 24, 26, "vcid", "VC ID", PRDV_HEX },
+ { 31, 31, "en", "VC Enable",
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_vc_rsrcsts[] = {
+ { 0, 0, "table", "Port Arbitration Table Status", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static void
+pcieadm_cfgspace_print_vc_rsrc(pcieadm_cfgspace_walk_t *walkp,
+ pcieadm_cfgspace_print_t *print, void *arg)
+{
+ uint32_t cap = walkp->pcw_data->pcb_u32[(walkp->pcw_capoff + 4) / 4];
+ uint32_t nents = BITX(cap, 2, 0) + 1;
+
+ for (uint32_t i = 0; i < nents; i++) {
+ char vcshort[32], vchuman[128];
+ pcieadm_cfgspace_print_t p;
+
+ (void) snprintf(vcshort, sizeof (vcshort), "rsrccap%u", i);
+ (void) snprintf(vchuman, sizeof (vchuman), "VC Resource %u "
+ "Capability", i);
+ p.pcp_off = print->pcp_off + i * 0x10;
+ p.pcp_len = 4;
+ p.pcp_short = vcshort;
+ p.pcp_human = vchuman;
+ p.pcp_print = pcieadm_cfgspace_print_regdef;
+ p.pcp_arg = pcieadm_regdef_vc_rsrccap;
+
+ p.pcp_print(walkp, &p, p.pcp_arg);
+
+ (void) snprintf(vcshort, sizeof (vcshort), "rsrcctl%u", i);
+ (void) snprintf(vchuman, sizeof (vchuman), "VC Resource %u "
+ "Control", i);
+ p.pcp_off = print->pcp_off + i * 0x10 + 4;
+ p.pcp_len = 4;
+ p.pcp_short = vcshort;
+ p.pcp_human = vchuman;
+ p.pcp_print = pcieadm_cfgspace_print_regdef;
+ p.pcp_arg = pcieadm_regdef_vc_rsrcctl;
+
+ p.pcp_print(walkp, &p, p.pcp_arg);
+
+ (void) snprintf(vcshort, sizeof (vcshort), "rsrcsts%u", i);
+ (void) snprintf(vchuman, sizeof (vchuman), "VC Resource %u "
+ "Status", i);
+ p.pcp_off = print->pcp_off + i * 0x10 + 0xa;
+ p.pcp_len = 2;
+ p.pcp_short = vcshort;
+ p.pcp_human = vchuman;
+ p.pcp_print = pcieadm_cfgspace_print_regdef;
+ p.pcp_arg = pcieadm_regdef_vc_rsrcsts;
+
+ p.pcp_print(walkp, &p, p.pcp_arg);
+ }
+}
+
+static pcieadm_cfgspace_print_t pcieadm_cap_vc[] = {
+ { 0x0, 4, "caphdr", "Capability Header",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
+ { 0x4, 4, "cap1", "Port VC Capability 1",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_vc_cap1 },
+ { 0x8, 4, "cap2", "Port VC Capability 2",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_vc_cap2 },
+ { 0xc, 2, "ctl", "Port VC Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_vc_ctl },
+ { 0xe, 2, "sts", "Port VC Status",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_vc_sts },
+ { 0x10, 12, "vcrec", "VC Resource", pcieadm_cfgspace_print_vc_rsrc },
+ { -1, -1, NULL }
+};
+
+/*
+ * HyperTransport
+ */
+static pcieadm_cfgspace_print_t pcieadm_cap_ht_intr[] = {
+ { 0x2, 1, "index", "Interrupt Discovery Index",
+ pcieadm_cfgspace_print_hex },
+ { 0x4, 4, "dataport", "Interrupt Dataport",
+ pcieadm_cfgspace_print_hex },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_ht_command_pri[] = {
+ { 0, 4, "unitid", "Base Unit ID", PRDV_HEX },
+ { 5, 9, "count", "Unit Count", PRDV_HEX },
+ { 10, 10, "host", "Master Host", PRDV_HEX },
+ { 11, 11, "dir", "Default Direction", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "towards host",
+ "away from host" } } },
+ { 12, 12, "drop", "Drop on Uninitialized Link", PRDV_HEX },
+ { 13, 15, "cap", "Capability ID", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_ht_command_sec[] = {
+ { 0, 0, "reset", "Warm Reset", PRDV_HEX },
+ { 1, 1, "de", "Double Ended", PRDV_HEX },
+ { 2, 6, "devno", "Device Number", PRDV_HEX },
+ { 7, 7, "chain", "Chain Side", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "from host", "from chain" } } },
+ { 8, 8, "hide", "Host Hide", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "visible", "hidden" } } },
+ { 10, 10, "target", "Act as Target", PRDV_HEX },
+ { 11, 11, "eocerr", "Host Inbound End of Chain Error", PRDV_HEX },
+ { 12, 12, "drop", "Drop on Uninitialized Link", PRDV_HEX },
+ { 13, 15, "cap", "Capability ID", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_ht_linkctl[] = {
+ { 0, 0, "srcid", "Source ID", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 1, 1, "cfl", "CRC Flood", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 2, 2, "cst", "CRC Start Test", PRDV_HEX },
+ { 3, 3, "cfer", "CRC Force Error", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 4, 4, "linkfail", "Link Failure", PRDV_HEX },
+ { 5, 5, "initcmp", "Initialization Complete", PRDV_HEX },
+ { 6, 6, "eoc", "End of Chain", PRDV_HEX },
+ { 7, 7, "txoff", "Transmitter Off", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "transmitter on",
+ "transmitter off" } } },
+ { 8, 11, "crcerr", "CRC Error", PRDV_HEX },
+ { 12, 12, "isoc", "Isochronous Flow Control", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 13, 13, "ls", "LDTSTOP# Tristate", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 14, 14, "extctl", "Extended CTL Time", PRDV_HEX },
+ { 15, 15, "64b", "64-bit Addressing", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_ht_linkcfg[] = {
+ { 0, 2, "maxin", "Maximum Link Width In", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "8 bits", "16 bits", NULL, "32 bits",
+ "2 bits", "4 bits", NULL, "not connected" } } },
+ { 3, 3, "dwfcinsup", "Doubleword Flow Control In", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 4, 6, "maxout", "Maximum Link Width Out", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "8 bits", "16 bits", NULL, "32 bits",
+ "2 bits", "4 bits", NULL, "not connected" } } },
+ { 7, 7, "dwfcoutsup", "Doubleword Flow Control Out", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 8, 10, "linkin", "Link Width In", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "8 bits", "16 bits", NULL, "32 bits",
+ "2 bits", "4 bits", NULL, "not connected" } } },
+ { 11, 11, "dwfcin", "Doubleword Flow Control In", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 12, 14, "linkout", "Link Width Out", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "8 bits", "16 bits", NULL, "32 bits",
+ "2 bits", "4 bits", NULL, "not connected" } } },
+ { 15, 15, "dwfcout", "Doubleword Flow Control Out", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_ht_rev[] = {
+ { 0, 4, "minor", "Minor Revision", PRDV_HEX },
+ { 5, 7, "major", "Major Revision", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_ht_linkfreq[] = {
+ { 0, 4, "freq", "Link Frequency", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "200 MHz", "300 MHz", "400 MHz",
+ "500 MHz", "600 MHz", "800 MHz", "1000 MHz", "1200 MHz", "1400 MHz",
+ "1600 MHz", "1800 MHz", "2000 MHz", "2200 MHz", "2400 MHz",
+ "2600 MHz", "Vendor Specfic" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_ht_linkerr[] = {
+ { 4, 4, "prot", "Protocol Error", PRDV_HEX },
+ { 5, 5, "over", "Overflow Error", PRDV_HEX },
+ { 6, 6, "eoc", "End of Chain Error", PRDV_HEX },
+ { 7, 7, "ctl", "CTL Timeout", PRDV_HEX },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_ht_linkcap[] = {
+ { 0, 15, "freq", "Link Frequency", PRDV_BITFIELD,
+ .prd_val = { .prdv_strval = { "200 MHz", "300 MHz", "400 MHz",
+ "500 MHz", "600 MHz", "800 MHz", "1000 MHz", "1200 MHz", "1400 MHz",
+ "1600 MHz", "1800 MHz", "2000 MHz", "2200 MHz", "2400 MHz",
+ "2600 MHz", "Vendor Specfic" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_ht_feature[] = {
+ { 0, 0, "isofc", "Isochronous Flow Control", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 1, 1, "ls", "LDTSTOP#", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 2, 2, "crct", "CRC Test Mode", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 3, 3, "ectl", "Extended CTL Time", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "not required", "required" } } },
+ { 4, 4, "64b", "64-bit Addressing", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 5, 5, "unitid", "UnitID Reorder", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "enabled", "disabled" } } },
+ { 6, 6, "srcid", "Source Identification Extension", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "not required", "required" } } },
+ { 8, 8, "extreg", "Extended Register Set", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
+ { 9, 9, "uscfg", "Upstream Configuration", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_ht_error[] = {
+ { 0, 0, "protfl", "Protocol Error Flood", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 1, 1, "ovfl", "Overflow Error Flood", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 2, 2, "protf", "Protocol Error Fatal", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 3, 3, "ovf", "Overflow Error Fatal", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 4, 4, "eocf", "End of Chain Fatal Error", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 5, 5, "respf", "Response Error Fatal", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 6, 6, "crcf", "CRC Error Fatal", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 7, 7, "sysf", "System Error Fatal", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 8, 8, "chain", "Chain Fail", PRDV_HEX },
+ { 9, 9, "resp", "Response Error", PRDV_HEX },
+ { 10, 10, "protnf", "Protocol Error Non-Fatal", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 11, 11, "ovfnf", "Overflow Error Non-Fatal", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 12, 12, "eocnf", "End of Chain Error Non-Fatal", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 13, 13, "respnf", "Response Error Non-Fatal", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 14, 14, "crcnf", "CRC Error Non-Fatal", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 15, 15, "sysnf", "System Error Non-Fatal", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_ht_memory[] = {
+ { 0, 8, "base", "Memory Base Upper 8 Bits", PRDV_HEX,
+ .prd_val = { .prdv_hex = { 32 } } },
+ { 9, 15, "limit", "Memory Limit Upper 8 Bits", PRDV_HEX,
+ .prd_val = { .prdv_hex = { 32 } } },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cap_ht_pri[] = {
+ { 0x2, 2, "command", "Command",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_command_pri },
+ { 0x4, 2, "linkctl0", "Link Control 0",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkctl },
+ { 0x6, 2, "linkcfg0", "Link Configuration 0",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkcfg },
+ { 0x8, 2, "linkctl1", "Link Control 1",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkctl },
+ { 0xa, 2, "linkcfg1", "Link Configuration 1",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkcfg },
+ { 0xc, 1, "rev", "Revision",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_rev },
+ { 0xd, 1, "linkfreq0", "Link Frequency 0",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkfreq },
+ { 0xd, 1, "linkerr0", "Link Error 0",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkerr },
+ { 0xe, 2, "linkfcap0", "Link Frequency Cap 0",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkcap },
+ { 0x10, 1, "feature", "Feature Capability",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_feature },
+ { 0x11, 1, "linkfreq1", "Link Frequency 1",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkfreq },
+ { 0x11, 1, "linkerr1", "Link Error 1",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkerr },
+ { 0x12, 2, "linkfcap1", "Link Frequency Cap 1",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkcap },
+ { 0x14, 2, "scratch", "Enumeration Scratchpad",
+ pcieadm_cfgspace_print_hex },
+ { 0x16, 2, "error", "Error Handling",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_error },
+ { 0x18, 2, "memory", "Memory",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_memory },
+ { 0x1a, 1, "bus", "Bus Number", pcieadm_cfgspace_print_hex },
+ { -1, -1, NULL }
+};
+
+static pcieadm_cfgspace_print_t pcieadm_cap_ht_sec[] = {
+ { 0x2, 2, "command", "Command",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_command_sec },
+ { 0x4, 2, "linkctl", "Link Control",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkctl },
+ { 0x6, 2, "linkcfg", "Link Configuration",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkcfg },
+ { 0x8, 1, "rev", "Revision",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_rev },
+ { 0x9, 1, "linkfreq", "Link Frequency 0",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkfreq },
+ { 0x9, 1, "linkerr", "Link Error 0",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkerr },
+ { 0xa, 2, "linkfcap", "Link Frequency Cap 0",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkcap },
+ { 0xc, 2, "feature", "Feature Capability",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_feature },
+ { 0x10, 2, "scratch", "Enumeration Scratchpad",
+ pcieadm_cfgspace_print_hex },
+ { 0x12, 2, "error", "Error Handling",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_error },
+ { 0x14, 2, "memory", "Memory",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_memory },
+ { -1, -1, NULL }
+};
+
+static pcieadm_regdef_t pcieadm_regdef_ht_msi[] = {
+ { 0, 0, "en", "Enable", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { 1, 1, "fixed", "Fixed", PRDV_STRVAL,
+ .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
+ { -1, -1, NULL }
+};
+
+static void
+pcieadm_cfgspace_print_ht_msi_addr(pcieadm_cfgspace_walk_t *walkp,
+ pcieadm_cfgspace_print_t *print, void *arg)
+{
+ uint8_t fixed = walkp->pcw_data->pcb_u8[walkp->pcw_capoff + 2];
+
+ if (BITX(fixed, 1, 1) != 0)
+ return;
+
+ pcieadm_cfgspace_print_hex(walkp, print, arg);
+}
+
+static pcieadm_cfgspace_print_t pcieadm_cap_ht_msi[] = {
+ { 0x2, 2, "command", "Command",
+ pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_msi },
+ { 0x4, 8, "address", "MSI Address",
+ pcieadm_cfgspace_print_ht_msi_addr },
+ { -1, -1, NULL }
+};
+
+/*
+ * Capability related tables
+ */
+typedef struct pcieadm_cap_vers {
+ uint32_t ppr_vers;
+ uint32_t ppr_len;
+ pcieadm_cfgspace_print_t *ppr_print;
+} pcieadm_cap_vers_t;
+
+typedef struct pcieadm_subcap {
+ const char *psub_short;
+ const char *psub_human;
+} pcieadm_subcap_t;
+
+typedef struct pcieadm_pci_cap pcieadm_pci_cap_t;
+
+typedef void (*pcieadm_cap_info_f)(pcieadm_cfgspace_walk_t *,
+ const pcieadm_pci_cap_t *, uint32_t, const pcieadm_cap_vers_t **,
+ uint32_t *, const pcieadm_subcap_t **);
+
+struct pcieadm_pci_cap {
+ uint32_t ppc_id;
+ const char *ppc_short;
+ const char *ppc_human;
+ pcieadm_cap_info_f ppc_info;
+ pcieadm_cap_vers_t ppc_vers[4];
+};
+
+/*
+ * Capability version determinations.
+ */
+
+static void
+pcieadm_cap_info_fixed(pcieadm_cfgspace_walk_t *walkp,
+ const pcieadm_pci_cap_t *cap, uint32_t off,
+ const pcieadm_cap_vers_t **versp, uint32_t *lenp,
+ const pcieadm_subcap_t **subcap)
+{
+ *versp = &cap->ppc_vers[0];
+ *lenp = cap->ppc_vers[0].ppr_len;
+ *subcap = NULL;
+}
+
+static void
+pcieadm_cap_info_vers(pcieadm_cfgspace_walk_t *walkp,
+ const pcieadm_pci_cap_t *cap, uint32_t off,
+ const pcieadm_cap_vers_t **versp, uint32_t *lenp,
+ const pcieadm_subcap_t **subcap)
+{
+ uint8_t vers;
+
+ *subcap = NULL;
+ vers = walkp->pcw_data->pcb_u8[off + 2] & 0xf;
+ for (uint32_t i = 0; i < ARRAY_SIZE(cap->ppc_vers); i++) {
+ if (vers == cap->ppc_vers[i].ppr_vers &&
+ cap->ppc_vers[i].ppr_vers != 0) {
+ *versp = &cap->ppc_vers[i];
+ *lenp = cap->ppc_vers[i].ppr_len;
+ return;
+ }
+ }
+
+ *versp = NULL;
+ *lenp = 0;
+}
+
+/*
+ * The PCI Power Management capability uses a 3-bit version ID as opposed to the
+ * standard 4-bit version.
+ */
+static void
+pcieadm_cap_info_pcipm(pcieadm_cfgspace_walk_t *walkp,
+ const pcieadm_pci_cap_t *cap, uint32_t off,
+ const pcieadm_cap_vers_t **versp, uint32_t *lenp,
+ const pcieadm_subcap_t **subcap)
+{
+ uint8_t vers;
+
+ *subcap = NULL;
+ vers = walkp->pcw_data->pcb_u8[off + 2] & 0x7;
+ for (uint32_t i = 0; i < ARRAY_SIZE(cap->ppc_vers); i++) {
+ if (vers == cap->ppc_vers[i].ppr_vers) {
+ *versp = &cap->ppc_vers[i];
+ *lenp = cap->ppc_vers[i].ppr_len;
+ return;
+ }
+ }
+
+ *versp = NULL;
+ *lenp = 0;
+}
+
+/*
+ * The length of the MSI capability depends on bits in its control field. As
+ * such we use a custom function to extract the length and treat each of these
+ * variants as thought it were a different version.
+ */
+static pcieadm_cap_vers_t pcieadm_cap_vers_msi_32 = {
+ 0, 0xa, pcieadm_cap_msi_32
+};
+
+static pcieadm_cap_vers_t pcieadm_cap_vers_msi_32ext = {
+ 0, 0xc, pcieadm_cap_msi_32ext
+};
+
+static pcieadm_cap_vers_t pcieadm_cap_vers_msi_64 = {
+ 0, 0xe, pcieadm_cap_msi_64
+};
+
+static pcieadm_cap_vers_t pcieadm_cap_vers_msi_64ext = {
+ 0, 0x10, pcieadm_cap_msi_64ext
+};
+
+static pcieadm_cap_vers_t pcieadm_cap_vers_msi_32pvm = {
+ 0, 0x14, pcieadm_cap_msi_32pvm
+};
+
+static pcieadm_cap_vers_t pcieadm_cap_vers_msi_64pvm = {
+ 0, 0x18, pcieadm_cap_msi_64pvm
+};
+
+static void
+pcieadm_cap_info_msi(pcieadm_cfgspace_walk_t *walkp,
+ const pcieadm_pci_cap_t *cap, uint32_t off,
+ const pcieadm_cap_vers_t **versp, uint32_t *lenp,
+ const pcieadm_subcap_t **subcap)
+{
+ uint16_t ctrl;
+ boolean_t addr64, pvm, ext;
+
+ *subcap = NULL;
+ ctrl = walkp->pcw_data->pcb_u8[off + 2] |
+ (walkp->pcw_data->pcb_u8[off + 3] << 8);
+ if (ctrl == PCI_EINVAL16) {
+ warnx("failed to read MSI Message Control register");
+ *lenp = 0;
+ *versp = NULL;
+ return;
+ }
+
+ /*
+ * The MSI capability has three main things that control its size.
+ * 64-bit addressing adds 4 bytes. Per-Vector Masking adds 8 bytes and
+ * causes the Extended data addressing piece to always be present.
+ * Therefore we check first for pvm as it implies evt, effectively.
+ */
+ addr64 = (ctrl & PCI_MSI_64BIT_MASK) != 0;
+ pvm = (ctrl & PCI_MSI_PVM_MASK) != 0;
+ ext = (ctrl & PCI_MSI_EMD_MASK) != 0;
+
+ if (pvm && addr64) {
+ *versp = &pcieadm_cap_vers_msi_64pvm;
+ } else if (pvm) {
+ *versp = &pcieadm_cap_vers_msi_32pvm;
+ } else if (addr64 && ext) {
+ *versp = &pcieadm_cap_vers_msi_64ext;
+ } else if (addr64) {
+ *versp = &pcieadm_cap_vers_msi_64;
+ } else if (ext) {
+ *versp = &pcieadm_cap_vers_msi_32ext;
+ } else {
+ *versp = &pcieadm_cap_vers_msi_32;
+ }
+
+ *lenp = (*versp)->ppr_len;
+}
+
+/*
+ * The AER Capability is technically different for PCIe-PCI bridges. If we find
+ * that device type here, then we need to use a different version information
+ * rather than the actual set defined with the device (which have changed over
+ * time).
+ */
+static const pcieadm_cap_vers_t pcieadm_cap_vers_aer_bridge = {
+ 1, 0x4c, pcieadm_cap_aer_bridge
+};
+
+static void
+pcieadm_cap_info_aer(pcieadm_cfgspace_walk_t *walkp,
+ const pcieadm_pci_cap_t *cap, uint32_t off,
+ const pcieadm_cap_vers_t **versp, uint32_t *lenp,
+ const pcieadm_subcap_t **subcap)
+{
+ if (walkp->pcw_dtype == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) {
+ uint8_t vers;
+
+ *subcap = NULL;
+ vers = walkp->pcw_data->pcb_u8[off + 2] & 0xf;
+ if (vers != pcieadm_cap_vers_aer_bridge.ppr_vers) {
+ warnx("encountered PCIe to PCI bridge with unknown "
+ "AER capability version: %u", vers);
+ *lenp = 0;
+ *versp = NULL;
+ return;
+ }
+ *lenp = pcieadm_cap_vers_aer_bridge.ppr_len;
+ *versp = &pcieadm_cap_vers_aer_bridge;
+ }
+
+ return (pcieadm_cap_info_vers(walkp, cap, off, versp, lenp, subcap));
+}
+
+/*
+ * The PCI-X capability varies depending on the header type of the device.
+ * Therefore we simply use the device type to figure out what to do.
+ */
+static pcieadm_cap_vers_t pcieadm_cap_vers_pcix_dev = {
+ 0, 0x8, pcieadm_cap_pcix_dev
+};
+
+static pcieadm_cap_vers_t pcieadm_cap_vers_pcix_bridge = {
+ 0, 0x10, pcieadm_cap_pcix_bridge
+};
+
+static void
+pcieadm_cap_info_pcix(pcieadm_cfgspace_walk_t *walkp,
+ const pcieadm_pci_cap_t *cap, uint32_t off,
+ const pcieadm_cap_vers_t **versp, uint32_t *lenp,
+ const pcieadm_subcap_t **subcap)
+{
+
+ *subcap = NULL;
+ switch (walkp->pcw_dtype) {
+ case PCI_HEADER_ZERO:
+ *versp = &pcieadm_cap_vers_pcix_dev;
+ break;
+ case PCI_HEADER_ONE:
+ *versp = &pcieadm_cap_vers_pcix_bridge;
+ break;
+ default:
+ warnx("encountered PCI-X capability with unsupported device "
+ "type: 0x%x\n", walkp->pcw_dtype);
+ *lenp = 0;
+ *versp = NULL;
+ return;
+ }
+
+ *lenp = (*versp)->ppr_len;
+}
+
+typedef struct pcieadm_cap_ht {
+ uint32_t pch_capid;
+ pcieadm_subcap_t pch_subcap;
+ pcieadm_cap_vers_t pch_vers;
+} pcieadm_cap_ht_t;
+
+static pcieadm_cap_ht_t pcieadm_ht_cap_pri = {
+ 0x00, { "pri", "Primary" }, { 0, 0x1c, pcieadm_cap_ht_pri }
+};
+
+static pcieadm_cap_ht_t pcieadm_ht_cap_sec = {
+ 0x01, { "sec", "Secondary" }, { 0, 0x18, pcieadm_cap_ht_sec }
+};
+
+static pcieadm_cap_ht_t pcieadm_ht_caps[] = {
+ { 0x08, { "switch", "Switch" } },
+ { 0x10, { "intr", "Interrupt Discovery and Configuration" },
+ { 0, 8, pcieadm_cap_ht_intr } },
+ { 0x11, { "rev", "Revision ID" } },
+ { 0x12, { "unitid", "UnitID Clumping" } },
+ { 0x13, { "extcfg", "Extended Configuration Space Access" } },
+ { 0x14, { "addrmap", "Address Mapping" } },
+ { 0x15, { "msi", "MSI Mapping" },
+ { 0, 4, pcieadm_cap_ht_msi } },
+ { 0x16, { "dir", "DirectRoute" } },
+ { 0x17, { "vcset", "VCSet" } },
+ { 0x18, { "retry", "Retry Mode" } },
+ { 0x19, { "x86", "X86 Encoding" } },
+ { 0x1a, { "gen3", "Gen3" } },
+ { 0x1b, { "fle", "Function-Level Extension" } },
+ { 0x1c, { "pm", "Power Management" } },
+ { UINT32_MAX, NULL },
+};
+
+static void
+pcieadm_cap_info_ht(pcieadm_cfgspace_walk_t *walkp,
+ const pcieadm_pci_cap_t *cap, uint32_t off,
+ const pcieadm_cap_vers_t **versp, uint32_t *lenp,
+ const pcieadm_subcap_t **subcap)
+{
+ uint32_t base = walkp->pcw_data->pcb_u32[off / 4];
+ uint32_t caplo = BITX(base, 31, 29);
+ pcieadm_cap_ht_t *htcap = NULL;
+
+ *versp = NULL;
+ *lenp = 0;
+ *subcap = NULL;
+
+ if (caplo > 1) {
+ uint32_t capid = BITX(base, 31, 27);
+
+ for (uint32_t i = 0; pcieadm_ht_caps[i].pch_capid != UINT32_MAX;
+ i++) {
+ if (capid == pcieadm_ht_caps[i].pch_capid) {
+ htcap = &pcieadm_ht_caps[i];
+ break;
+ }
+ }
+ } else if (caplo == 0) {
+ htcap = &pcieadm_ht_cap_pri;
+ } else if (caplo == 1) {
+ htcap = &pcieadm_ht_cap_sec;
+ }
+
+ if (htcap == NULL) {
+ warnx("encountered unknown HyperTransport Capability 0x%x",
+ BITX(base, 31, 27));
+ return;
+ }
+
+ *subcap = &htcap->pch_subcap;
+ if (htcap->pch_vers.ppr_print != NULL) {
+ *versp = &htcap->pch_vers;
+ *lenp = htcap->pch_vers.ppr_len;
+ }
+}
+
+pcieadm_pci_cap_t pcieadm_pci_caps[] = {
+ { PCI_CAP_ID_PM, "pcipm", "PCI Power Management",
+ pcieadm_cap_info_pcipm, { { 2, 8, pcieadm_cap_pcipm_v3 },
+ { 3, 8, pcieadm_cap_pcipm_v3 } } },
+ { PCI_CAP_ID_AGP, "agp", "Accelerated Graphics Port" },
+ { PCI_CAP_ID_VPD, "vpd", "Vital Product Data", pcieadm_cap_info_fixed,
+ { { 0, 8, pcieadm_cap_vpd } } },
+ { PCI_CAP_ID_SLOT_ID, "slot", "Slot Identification" },
+ { PCI_CAP_ID_MSI, "msi", "Message Signaled Interrupts",
+ pcieadm_cap_info_msi },
+ { PCI_CAP_ID_cPCI_HS, "cpci", "CompactPCI Hot Swap" },
+ { PCI_CAP_ID_PCIX, "pcix", "PCI-X", pcieadm_cap_info_pcix },
+ { PCI_CAP_ID_HT, "ht", "HyperTransport", pcieadm_cap_info_ht },
+ { PCI_CAP_ID_VS, "vs", "Vendor Specific", pcieadm_cap_info_fixed,
+ { { 0, 3, pcieadm_cap_vs } } },
+ { PCI_CAP_ID_DEBUG_PORT, "dbg", "Debug Port", pcieadm_cap_info_fixed,
+ { { 0, 4, pcieadm_cap_debug } } },
+ { PCI_CAP_ID_cPCI_CRC, "cpcicrc",
+ "CompactPCI Central Resource Control" },
+ { PCI_CAP_ID_PCI_HOTPLUG, "pcihp", "PCI Hot-Plug" },
+ { PCI_CAP_ID_P2P_SUBSYS, "bdgsub", "PCI Bridge Subsystem Vendor ID",
+ pcieadm_cap_info_fixed, { 0, 8, pcieadm_cap_bridge_subsys } },
+ { PCI_CAP_ID_AGP_8X, "agp8x", "AGP 8x" },
+ { PCI_CAP_ID_SECURE_DEV, "secdev", "Secure Device" },
+ { PCI_CAP_ID_PCI_E, "pcie", "PCI Express", pcieadm_cap_info_vers,
+ { { 1, 0x24, pcieadm_cap_pcie_v1 },
+ { 2, 0x3c, pcieadm_cap_pcie_v2 } } },
+ { PCI_CAP_ID_MSI_X, "msix", "MSI-X", pcieadm_cap_info_fixed,
+ { { 0, 12, pcieadm_cap_msix } } },
+ { PCI_CAP_ID_SATA, "sata", "Serial ATA Configuration",
+ pcieadm_cap_info_fixed, { { 0, 8, pcieadm_cap_sata } } },
+ /*
+ * Note, the AF feature doesn't have a version but encodes a length in
+ * the version field, so we cheat and use that.
+ */
+ { PCI_CAP_ID_FLR, "af", "Advanced Features", pcieadm_cap_info_vers,
+ { { 6, 6, pcieadm_cap_af } } },
+ { PCI_CAP_ID_EA, "ea", "Enhanced Allocation" },
+ { PCI_CAP_ID_FPB, "fpb", "Flattening Portal Bridge" }
+};
+
+pcieadm_pci_cap_t pcieadm_pcie_caps[] = {
+ { 0, "null", "NULL Capability", pcieadm_cap_info_fixed,
+ { { 0, 0x4, pcieadm_cap_null } } },
+ { PCIE_EXT_CAP_ID_AER, "aer", "Advanced Error Reporting",
+ pcieadm_cap_info_aer, { { 1, 0x38, pcieadm_cap_aer_v1 },
+ { 2, 0x48, pcieadm_cap_aer_v2 } } },
+ { PCIE_EXT_CAP_ID_VC, "vc", "Virtual Channel", pcieadm_cap_info_vers,
+ { { 0x1, 0x1c, pcieadm_cap_vc } } },
+ { PCIE_EXT_CAP_ID_SER, "sn", "Serial Number", pcieadm_cap_info_vers,
+ { { 1, 0xc, pcieadm_cap_sn } } },
+ { PCIE_EXT_CAP_ID_PWR_BUDGET, "powbudg", "Power Budgeting",
+ pcieadm_cap_info_vers, { { 1, 0x10, pcieadm_cap_powbudg } } },
+ { PCIE_EXT_CAP_ID_RC_LINK_DECL, "rcld",
+ "Root Complex Link Declaration" },
+ { PCIE_EXT_CAP_ID_RC_INT_LINKCTRL, "rcilc",
+ "Root Complex Internal Link Control" },
+ { PCIE_EXT_CAP_ID_RC_EVNT_CEA, "rcecea",
+ "Root Complex Event Collector Endpoint Aggregation" },
+ { PCIE_EXT_CAP_ID_MFVC, "mfvc", "Multi-Function Virtual Channel" },
+ { PCIE_EXT_CAP_ID_VC_WITH_MFVC, "vcwmfvc", "Virtual Channel with MFVC",
+ pcieadm_cap_info_vers, { { 0x1, 0x1c, pcieadm_cap_vc } } },
+ { PCIE_EXT_CAP_ID_RCRB, "rcrb", "Root Complex Register Block" },
+ { PCIE_EXT_CAP_ID_VS, "vsec", "Vendor Specific Extended Capability",
+ pcieadm_cap_info_vers, { { 1, 0x8, pcieadm_cap_vsec } } },
+ { PCIE_EXT_CAP_ID_CAC, "cac", "Configuration Access Correlation" },
+ { PCIE_EXT_CAP_ID_ACS, "acs", "Access Control Services",
+ pcieadm_cap_info_vers, { { 1, 0x8, pcieadm_cap_acs } } },
+ { PCIE_EXT_CAP_ID_ARI, "ari", "Alternative Routing-ID Interpretation",
+ pcieadm_cap_info_vers, { { 1, 0x8, pcieadm_cap_ari } } },
+ { PCIE_EXT_CAP_ID_ATS, "ats", "Access Translation Services",
+ pcieadm_cap_info_vers, { { 1, 0x8, pcieadm_cap_ats } } },
+ { PCIE_EXT_CAP_ID_SRIOV, "sriov", "Single Root I/O Virtualization",
+ pcieadm_cap_info_vers, { { 1, 0x40, pcieadm_cap_sriov } } },
+ { PCIE_EXT_CAP_ID_MRIOV, "mriov", "Multi-Root I/O Virtualization" },
+ { PCIE_EXT_CAP_ID_MULTICAST, "mcast", "Multicast",
+ pcieadm_cap_info_vers, { { 1, 0x30, pcieadm_cap_mcast } } },
+ { PCIE_EXT_CAP_ID_PGREQ, "pgreq", "Page Request",
+ pcieadm_cap_info_vers, { { 1, 0x10, pcieadm_cap_pgreq } } },
+ { PCIE_EXT_CAP_ID_EA, "ea", "Enhanced Allocation" },
+ { PCIE_EXT_CAP_ID_RESIZE_BAR, "rbar", "Resizable Bar" },
+ { PCIE_EXT_CAP_ID_DPA, "dpa", "Dynamic Power Allocation",
+ pcieadm_cap_info_vers, { { 1, 0x10, pcieadm_cap_dpa } } },
+ { PCIE_EXT_CAP_ID_TPH_REQ, "tph", "TPH Requester",
+ pcieadm_cap_info_vers, { { 1, 0xc, pcieadm_cap_tph } } },
+ { PCIE_EXT_CAP_ID_LTR, "ltr", "Latency Tolerance Reporting",
+ pcieadm_cap_info_vers, { { 1, 0x8, pcieadm_cap_ltr } } },
+ { PCIE_EXT_CAP_ID_PCIE2, "pcie2", "Secondary PCI Express",
+ pcieadm_cap_info_vers, { { 1, 0xc, pcieadm_cap_pcie2 } } },
+ { PCIE_EXT_CAP_ID_PASID, "pasid", "Process Address Space ID",
+ pcieadm_cap_info_vers, { { 1, 0x8, pcieadm_cap_pasid } } },
+ { PCIE_EXT_CAP_ID_LNR, "lnr", "LN Requester" },
+ { PCIE_EXT_CAP_ID_DPC, "dpc", "Downstream Port Containment",
+ pcieadm_cap_info_vers, { { 1, 0x30, pcieadm_cap_dpc } } },
+ { PCIE_EXT_CAP_ID_L1PM, "l1pm", "L1 PM Substates",
+ pcieadm_cap_info_vers, { { 1, 0x10, pcieadm_cap_l1pm_v1 },
+ { 2, 0x14, pcieadm_cap_l1pm_v2 } } },
+ { PCIE_EXT_CAP_ID_PTM, "ptm", "Precision Time Management",
+ pcieadm_cap_info_vers, { { 1, 0xc, pcieadm_cap_info_ptm } } },
+ { PCIE_EXT_CAP_ID_FRS, "frs", "FRS Queueing" },
+ { PCIE_EXT_CAP_ID_RTR, "trt", "Readiness Time Reporting" },
+ /*
+ * When we encounter a designated vendor specificaiton, in particular,
+ * for CXL, we'll want to set ppc_subcap so we can use reasonable
+ * filtering.
+ */
+ { PCIE_EXT_CAP_ID_DVS, "dvsec",
+ "Designated Vendor-Specific Extended Capability" },
+ { PCIE_EXT_CAP_ID_VFRBAR, "vfrbar", "Virtual Function Resizable BAR" },
+ { PCIE_EXT_CAP_ID_DLF, "dlf", "Data Link Feature",
+ pcieadm_cap_info_vers, { { 1, 0xc, pcieadm_cap_dlf } } },
+ { PCIE_EXT_CAP_ID_PL16GT, "pl16g", "Physical Layer 16.0 GT/s",
+ pcieadm_cap_info_vers, { { 1, 0x22, pcieadm_cap_16g } } },
+ { PCIE_EXT_CAP_ID_LANE_MARGIN, "margin",
+ "Lane Margining at the Receiver", pcieadm_cap_info_vers,
+ { { 1, 0x8, pcieadm_cap_margin } } },
+ { PCIE_EXT_CAP_ID_HIEARCHY_ID, "hierid", "Hierarchy ID" },
+ { PCIE_EXT_CAP_ID_NPEM, "npem", "Native PCIe Enclosure Management" },
+ { PCIE_EXT_CAP_ID_PL32GT, "pl32g", "Physical Layer 32.0 GT/s" },
+ { PCIE_EXT_CAP_ID_AP, "ap", "Alternative Protocol" },
+ { PCIE_EXT_CAP_ID_SFI, "sfi", "System Firmware Intermediary" }
+};
+
+static const pcieadm_pci_cap_t *
+pcieadm_cfgspace_match_cap(uint32_t capid, boolean_t pcie)
+{
+ uint_t ncaps;
+ pcieadm_pci_cap_t *caps;
+
+ if (pcie) {
+ ncaps = ARRAY_SIZE(pcieadm_pcie_caps);
+ caps = pcieadm_pcie_caps;
+ } else {
+ ncaps = ARRAY_SIZE(pcieadm_pci_caps);
+ caps = pcieadm_pci_caps;
+ }
+
+ for (uint_t i = 0; i < ncaps; i++) {
+ if (caps[i].ppc_id == capid) {
+ return (&caps[i]);
+ }
+ }
+
+ return (NULL);
+}
+
+static void
+pcieadm_cfgspace_print_cap(pcieadm_cfgspace_walk_t *walkp, uint_t capid,
+ const pcieadm_pci_cap_t *cap_info, const pcieadm_cap_vers_t *vers_info,
+ const pcieadm_subcap_t *subcap)
+{
+ boolean_t filter = B_FALSE;
+
+ /*
+ * If we don't recognize the capability, print out the ID if we're not
+ * filtering and not in parsable mode.
+ */
+ if (cap_info == NULL) {
+ if (walkp->pcw_ofmt == NULL &&
+ pcieadm_cfgspace_filter(walkp, NULL)) {
+ warnx("encountered unknown capability ID 0x%x "
+ "unable to print or list", capid);
+ pcieadm_print("Unknown Capability (0x%x)\n", capid);
+ }
+ return;
+ }
+
+ /*
+ * Check to see if we should print this and in particular, if there's
+ * both a capability or subcapability, we need to try and match both.
+ * The reason that the calls to check the filters are conditioned on
+ * pcw_ofmt is that when we're in parsable mode, we cannot match a
+ * top-level capability since it's an arbitrary number of fields.
+ */
+ if (walkp->pcw_ofmt == NULL) {
+ filter = pcieadm_cfgspace_filter(walkp, cap_info->ppc_short);
+ }
+ pcieadm_strfilt_push(walkp, cap_info->ppc_short);
+ if (subcap != NULL) {
+ if (walkp->pcw_ofmt == NULL) {
+ boolean_t subfilt = pcieadm_cfgspace_filter(walkp,
+ subcap->psub_short);
+ filter = subfilt || filter;
+ }
+ pcieadm_strfilt_push(walkp, subcap->psub_short);
+ }
+
+
+ if (walkp->pcw_ofmt == NULL && filter) {
+ if ((walkp->pcw_flags & PCIEADM_CFGSPACE_F_SHORT) != 0) {
+ if (subcap != NULL) {
+ pcieadm_print("%s Capability - %s (%s) "
+ "(0x%x)\n", cap_info->ppc_human,
+ subcap->psub_human,
+ walkp->pcw_filt->pstr_curgen, capid);
+ } else {
+ pcieadm_print("%s Capability (%s) (0x%x)\n",
+ cap_info->ppc_human,
+ walkp->pcw_filt->pstr_curgen, capid);
+ }
+ } else {
+ if (subcap != NULL) {
+ pcieadm_print("%s Capability - %s (0x%x)\n",
+ cap_info->ppc_human, subcap->psub_human,
+ capid);
+ } else {
+ pcieadm_print("%s Capability (0x%x)\n",
+ cap_info->ppc_human, capid);
+ }
+ }
+ }
+
+ if (vers_info != NULL) {
+ pcieadm_cfgspace_print_t *print;
+
+ pcieadm_indent();
+ for (print = vers_info->ppr_print;
+ print->pcp_short != NULL; print++) {
+ VERIFY3P(print->pcp_print, !=, NULL);
+ print->pcp_print(walkp, print,
+ print->pcp_arg);
+ }
+ pcieadm_deindent();
+ } else {
+ if (subcap != NULL) {
+ warnx("Unable to print or list %s - %s (no support or "
+ "missing version info)", cap_info->ppc_human,
+ subcap->psub_human);
+ } else {
+ warnx("Unable to print or list %s (no support or "
+ "missing version info)", cap_info->ppc_human);
+ }
+ }
+
+ if (subcap != NULL) {
+ pcieadm_strfilt_pop(walkp);
+ }
+ pcieadm_strfilt_pop(walkp);
+}
+
+static void
+pcieadm_cfgspace_write(int fd, const uint8_t *source, size_t len)
+{
+ size_t off = 0;
+
+ while (len > 0) {
+ ssize_t ret = write(fd, source + off, len - off);
+ if (ret < 0) {
+ err(EXIT_FAILURE, "failed to write config space to "
+ "output file");
+ }
+
+ off += ret;
+ len -= ret;
+ }
+}
+
+void
+pcieadm_cfgspace(pcieadm_t *pcip, pcieadm_cfgspace_op_t op,
+ pcieadm_cfgspace_f readf, int fd, void *readarg, uint_t nfilts,
+ pcieadm_cfgspace_filter_t *filters, pcieadm_cfgspace_flags_t flags,
+ ofmt_handle_t ofmt)
+{
+ uint_t type;
+ uint16_t cap;
+ pcieadm_cfgspace_data_t data;
+ pcieadm_cfgspace_walk_t walk;
+ const char *headstr, *headshort;
+ pcieadm_cfgspace_print_t *header;
+ boolean_t capsup = B_FALSE, extcfg = B_FALSE;
+ uint_t ncaps;
+
+ walk.pcw_pcieadm = pcip;
+ walk.pcw_op = op;
+ walk.pcw_data = &data;
+ walk.pcw_outfd = fd;
+ walk.pcw_capoff = 0;
+ walk.pcw_nlanes = 0;
+ walk.pcw_nfilters = nfilts;
+ walk.pcw_filters = filters;
+ walk.pcw_flags = flags;
+ walk.pcw_ofmt = ofmt;
+ walk.pcw_filt = NULL;
+
+ /*
+ * Start by reading all of the basic 40-byte config space header in one
+ * fell swoop.
+ */
+ for (uint32_t i = 0; i < PCI_CAP_PTR_OFF / 4; i++) {
+ if (!readf(i * 4, 4, &data.pcb_u32[i], readarg)) {
+ errx(EXIT_FAILURE, "failed to read offset %u from "
+ "configuration space", i * 4);
+ }
+ }
+ walk.pcw_valid = PCI_CAP_PTR_OFF;
+ walk.pcw_caplen = PCI_CAP_PTR_OFF;
+
+ /*
+ * Grab the information from the header that we need to figure out what
+ * kind of device this is, how to print it, if there are any
+ * capabilities, and go from there.
+ */
+ type = data.pcb_u8[PCI_CONF_HEADER] & PCI_HEADER_TYPE_M;
+ switch (type) {
+ case PCI_HEADER_ZERO:
+ headstr = "Type 0 Header";
+ headshort = "header0";
+ header = pcieadm_cfgspace_type0;
+ capsup = (data.pcb_u8[PCI_CONF_STAT] & PCI_STAT_CAP) != 0;
+ break;
+ case PCI_HEADER_ONE:
+ headstr = "Type 1 Header";
+ headshort = "header1";
+ header = pcieadm_cfgspace_type1;
+ capsup = (data.pcb_u8[PCI_CONF_STAT] & PCI_STAT_CAP) != 0;
+ break;
+ case PCI_HEADER_TWO:
+ default:
+ headstr = "Unknown Header";
+ headshort = "headerX";
+ header = pcieadm_cfgspace_unknown;
+ warnx("unsupported PCI header type: 0x%x, output limited to "
+ "data configuration space");
+ }
+
+ walk.pcw_dtype = type;
+
+ if (op == PCIEADM_CFGSPACE_OP_WRITE) {
+ pcieadm_cfgspace_write(fd, &data.pcb_u8[0], PCI_CAP_PTR_OFF);
+ } else if (op == PCIEADM_CFGSPACE_OP_PRINT) {
+ pcieadm_cfgspace_print_t *print;
+
+ if (walk.pcw_ofmt == NULL &&
+ pcieadm_cfgspace_filter(&walk, headshort)) {
+ if ((flags & PCIEADM_CFGSPACE_F_SHORT) != 0) {
+ pcieadm_print("Device %s -- %s (%s)\n",
+ pcip->pia_devstr, headstr, headshort);
+ } else {
+ pcieadm_print("Device %s -- %s\n",
+ pcip->pia_devstr, headstr);
+ }
+ }
+
+ pcieadm_strfilt_push(&walk, headshort);
+ pcieadm_indent();
+ for (print = header; print->pcp_short != NULL; print++) {
+ print->pcp_print(&walk, print, print->pcp_arg);
+ }
+ pcieadm_deindent();
+ pcieadm_strfilt_pop(&walk);
+ }
+
+
+ if (!capsup) {
+ return;
+ }
+
+ for (uint32_t i = PCI_CAP_PTR_OFF / 4; i < PCI_CONF_HDR_SIZE / 4; i++) {
+ if (!readf(i * 4, 4, &data.pcb_u32[i], readarg)) {
+ errx(EXIT_FAILURE, "failed to read offset %u from "
+ "configuration space", i * 4);
+ }
+ }
+ walk.pcw_valid = PCIE_EXT_CAP;
+ VERIFY3P(walk.pcw_filt, ==, NULL);
+
+ if (op == PCIEADM_CFGSPACE_OP_WRITE) {
+ pcieadm_cfgspace_write(fd, &data.pcb_u8[PCI_CAP_PTR_OFF],
+ PCI_CONF_HDR_SIZE - PCI_CAP_PTR_OFF);
+ }
+
+ ncaps = 0;
+ cap = data.pcb_u8[PCI_CONF_CAP_PTR];
+ while (cap != 0 && cap != PCI_EINVAL8) {
+ const pcieadm_pci_cap_t *cap_info;
+ const pcieadm_cap_vers_t *vers_info = NULL;
+ const pcieadm_subcap_t *subcap = NULL;
+ uint8_t cap_id, nextcap;
+ uint32_t read_len = 0;
+
+ /*
+ * The PCI specification requires that the caller mask off the
+ * bottom two bits. Always check for an invalid value (all 1s)
+ * before this.
+ */
+ cap &= PCI_CAP_PTR_MASK;
+ cap_id = data.pcb_u8[cap + PCI_CAP_ID];
+ nextcap = data.pcb_u8[cap + PCI_CAP_NEXT_PTR];
+ cap_info = pcieadm_cfgspace_match_cap(cap_id, B_FALSE);
+ if (cap_info != NULL && cap_info->ppc_info != NULL) {
+ cap_info->ppc_info(&walk, cap_info, cap, &vers_info,
+ &read_len, &subcap);
+ }
+
+ walk.pcw_caplen = read_len;
+ walk.pcw_capoff = cap;
+
+ if (cap_id == PCI_CAP_ID_PCI_E) {
+ extcfg = B_TRUE;
+ if (walk.pcw_valid != 0) {
+ walk.pcw_pcietype = data.pcb_u8[cap +
+ PCIE_PCIECAP] & PCIE_PCIECAP_DEV_TYPE_MASK;
+ walk.pcw_nlanes = (data.pcb_u8[cap +
+ PCIE_LINKCAP] & 0xf0) >> 4;
+ walk.pcw_nlanes |= (data.pcb_u8[cap +
+ PCIE_LINKCAP + 1] & 0x01) << 4;
+ } else {
+ walk.pcw_pcietype = UINT_MAX;
+ }
+ }
+
+ if (op == PCIEADM_CFGSPACE_OP_PRINT) {
+ pcieadm_cfgspace_print_cap(&walk, cap_id, cap_info,
+ vers_info, subcap);
+ }
+
+ cap = nextcap;
+ ncaps++;
+ if (ncaps >= PCI_CAP_MAX_PTR) {
+ errx(EXIT_FAILURE, "encountered more PCI capabilities "
+ "than fit in configuration space");
+ }
+ }
+
+ if (!extcfg) {
+ return;
+ }
+
+ for (uint_t i = PCIE_EXT_CAP / 4; i < PCIE_CONF_HDR_SIZE / 4; i++) {
+ if (!readf(i * 4, 4, &data.pcb_u32[i], readarg)) {
+ errx(EXIT_FAILURE, "failed to read offset %u from "
+ "configuration space", i * 4);
+ }
+ }
+ walk.pcw_valid = PCIE_CONF_HDR_SIZE;
+
+ if (op == PCIEADM_CFGSPACE_OP_WRITE) {
+ pcieadm_cfgspace_write(fd, &data.pcb_u8[PCIE_EXT_CAP],
+ PCIE_CONF_HDR_SIZE - PCIE_EXT_CAP);
+ return;
+ }
+
+ cap = PCIE_EXT_CAP;
+ ncaps = 0;
+ while (cap != 0 && cap != PCI_EINVAL16) {
+ uint16_t cap_id, nextcap;
+ const pcieadm_pci_cap_t *cap_info;
+ const pcieadm_cap_vers_t *vers_info = NULL;
+ const pcieadm_subcap_t *subcap = NULL;
+ uint32_t read_len = 0;
+
+ /*
+ * PCIe has the same masking as PCI. Note, sys/pcie.h currently
+ * has PCIE_EXT_CAP_NEXT_PTR_MASK as 0xfff, instead of the
+ * below. This should be switched to PCIE_EXT_CAP_NEXT_PTR_MASK
+ * when the kernel headers are fixed.
+ */
+ cap &= 0xffc;
+
+ /*
+ * While this seems duplicative of the loop condition, a device
+ * without capabilities indicates it with a zero for the first
+ * cap.
+ */
+ if (data.pcb_u32[cap / 4] == 0 ||
+ data.pcb_u32[cap / 4] == PCI_EINVAL32)
+ break;
+
+ cap_id = data.pcb_u32[cap / 4] & PCIE_EXT_CAP_ID_MASK;
+ nextcap = (data.pcb_u32[cap / 4] >>
+ PCIE_EXT_CAP_NEXT_PTR_SHIFT) & PCIE_EXT_CAP_NEXT_PTR_MASK;
+
+ cap_info = pcieadm_cfgspace_match_cap(cap_id, B_TRUE);
+ if (cap_info != NULL && cap_info->ppc_info != NULL) {
+ cap_info->ppc_info(&walk, cap_info, cap, &vers_info,
+ &read_len, &subcap);
+ }
+
+ walk.pcw_caplen = read_len;
+ walk.pcw_capoff = cap;
+
+ if (op == PCIEADM_CFGSPACE_OP_PRINT) {
+ pcieadm_cfgspace_print_cap(&walk, cap_id, cap_info,
+ vers_info, subcap);
+ }
+
+ cap = nextcap;
+ ncaps++;
+ if (ncaps >= PCIE_EXT_CAP_MAX_PTR) {
+ errx(EXIT_FAILURE, "encountered more PCI capabilities "
+ "than fit in configuration space");
+ }
+ }
+}
+
+void
+pcieadm_show_cfgspace_usage(FILE *f)
+{
+ (void) fprintf(f, "\tshow-cfgspace\t[-L] [-n] [-H] -d device | -f file "
+ "[filter...]\n");
+ (void) fprintf(f, "\tshow-cfgspace\t-p -o field[,...] [-H] -d device | "
+ "-f file [filter...]\n");
+}
+
+static void
+pcieadm_show_cfgspace_help(const char *fmt, ...)
+{
+ if (fmt != NULL) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ vwarnx(fmt, ap);
+ va_end(ap);
+ (void) fprintf(stderr, "\n");
+ }
+
+ (void) fprintf(stderr, "Usage: %s show-cfgspace [-L] [-n] [-H] -d "
+ "device | -f file [filter...]\n", pcieadm_progname);
+ (void) fprintf(stderr, " %s show-cfgspace -p -o field[,...] "
+ "[-H] -d device | -f file\n\t\t\t [filter...]\n",
+ pcieadm_progname);
+
+ (void) fprintf(stderr, "\nPrint and decode PCI configuration space "
+ "data from a device or file. Each\n<filter> selects a given "
+ "capability, sub-capability, register, or field to print.\n\n"
+ "\t-d device\tread data from the specified device (driver instance,"
+ "\n\t\t\t/devices path, or b/d/f)\n"
+ "\t-f file\t\tread data from the specified file\n"
+ "\t-L\t\tlist printable fields\n"
+ "\t-n\t\tshow printable short names\n"
+ "\t-H\t\tomit the column header (for -L and -p)\n"
+ "\t-p\t\tparsable output (requires -o)\n"
+ "\t-o field\toutput fields to print (required for -p)\n");
+}
+
+int
+pcieadm_show_cfgspace(pcieadm_t *pcip, int argc, char *argv[])
+{
+ int c, ret;
+ pcieadm_cfgspace_f readf;
+ void *readarg;
+ boolean_t list = B_FALSE, parse = B_FALSE;
+ const char *device = NULL, *file = NULL, *fields = NULL;
+ uint_t nfilts = 0;
+ pcieadm_cfgspace_filter_t *filts = NULL;
+ pcieadm_cfgspace_flags_t flags = 0;
+ uint_t oflags = 0;
+ ofmt_handle_t ofmt = NULL;
+
+ while ((c = getopt(argc, argv, ":HLd:f:o:np")) != -1) {
+ switch (c) {
+ case 'd':
+ device = optarg;
+ break;
+ case 'L':
+ list = B_TRUE;
+ break;
+ case 'f':
+ file = optarg;
+ break;
+ case 'p':
+ parse = B_TRUE;
+ flags |= PCIEADM_CFGSPACE_F_PARSE;
+ oflags |= OFMT_PARSABLE;
+ break;
+ case 'n':
+ flags |= PCIEADM_CFGSPACE_F_SHORT;
+ break;
+ case 'H':
+ oflags |= OFMT_NOHEADER;
+ break;
+ case 'o':
+ fields = optarg;
+ break;
+ case ':':
+ pcieadm_show_cfgspace_help("Option -%c requires an "
+ "argument", optopt);
+ exit(EXIT_USAGE);
+ case '?':
+ default:
+ pcieadm_show_cfgspace_help("unknown option: -%c",
+ optopt);
+ exit(EXIT_USAGE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (device == NULL && file == NULL) {
+ pcieadm_show_cfgspace_help("one of -d or -f must be specified");
+ exit(EXIT_USAGE);
+ }
+
+ if (device != NULL && file != NULL) {
+ pcieadm_show_cfgspace_help("only one of -d and -f must be "
+ "specified");
+ exit(EXIT_USAGE);
+ }
+
+ if (parse && fields == NULL) {
+ pcieadm_show_cfgspace_help("-p requires fields specified with "
+ "-o");
+ exit(EXIT_USAGE);
+ }
+
+ if (!parse && fields != NULL) {
+ pcieadm_show_cfgspace_help("-o can only be used with -p");
+ exit(EXIT_USAGE);
+ }
+
+ if ((oflags & OFMT_NOHEADER) && !(list || parse)) {
+ pcieadm_show_cfgspace_help("-H must be used with either -L or "
+ "-p");
+ exit(EXIT_USAGE);
+ }
+
+ if ((flags & PCIEADM_CFGSPACE_F_SHORT) && (list || parse)) {
+ pcieadm_show_cfgspace_help("-n cannot be used with either -L "
+ "or -p");
+ exit(EXIT_USAGE);
+ }
+
+ if (list && parse != 0) {
+ pcieadm_show_cfgspace_help("-L and -p cannot be used together");
+ exit(EXIT_USAGE);
+ }
+
+ if (list && fields != NULL) {
+ pcieadm_show_cfgspace_help("-L and -o cannot be used together");
+ exit(EXIT_USAGE);
+ }
+
+ if (list) {
+ fields = "short,human";
+ }
+
+ if (argc > 0) {
+ nfilts = argc;
+ filts = calloc(nfilts, sizeof (pcieadm_cfgspace_filter_t));
+
+ for (int i = 0; i < argc; i++) {
+ filts[i].pcf_string = argv[i];
+ filts[i].pcf_len = strlen(argv[i]);
+ }
+ }
+
+ if (list || parse) {
+ ofmt_status_t oferr;
+ oferr = ofmt_open(fields, pcieadm_cfgspace_ofmt, oflags, 0,
+ &ofmt);
+ ofmt_check(oferr, parse, ofmt, pcieadm_ofmt_errx, warnx);
+ }
+
+ /*
+ * Initialize privileges that we require. For reading from the kernel
+ * we require all privileges. For a file, we just intersect with things
+ * that would allow someone to read from any file.
+ */
+ if (device != NULL) {
+ /*
+ * We need full privileges if reading from a device,
+ * unfortunately.
+ */
+ priv_fillset(pcip->pia_priv_eff);
+ } else {
+ VERIFY0(priv_addset(pcip->pia_priv_eff, PRIV_FILE_DAC_READ));
+ VERIFY0(priv_addset(pcip->pia_priv_eff, PRIV_FILE_DAC_SEARCH));
+ }
+ pcieadm_init_privs(pcip);
+
+ if (device != NULL) {
+ pcieadm_find_dip(pcip, device);
+ pcieadm_init_cfgspace_kernel(pcip, &readf, &readarg);
+ } else {
+ pcip->pia_devstr = file;
+ pcieadm_init_cfgspace_file(pcip, file, &readf, &readarg);
+ }
+ pcieadm_cfgspace(pcip, PCIEADM_CFGSPACE_OP_PRINT, readf, -1, readarg,
+ nfilts, filts, flags, ofmt);
+ if (device != NULL) {
+ pcieadm_fini_cfgspace_kernel(readarg);
+ } else {
+ pcieadm_fini_cfgspace_file(readarg);
+ }
+
+ ofmt_close(ofmt);
+ ret = EXIT_SUCCESS;
+ for (uint_t i = 0; i < nfilts; i++) {
+ if (!filts[i].pcf_used) {
+ warnx("filter '%s' did not match any fields",
+ filts[i].pcf_string);
+ ret = EXIT_FAILURE;
+ }
+ }
+
+ return (ret);
+}
+
+typedef struct pcieadm_save_cfgspace {
+ pcieadm_t *psc_pci;
+ int psc_dirfd;
+ uint_t psc_nsaved;
+ int psc_ret;
+} pcieadm_save_cfgspace_t;
+
+static int
+pcieadm_save_cfgspace_cb(di_node_t devi, void *arg)
+{
+ int fd, nregs, *regs;
+ pcieadm_save_cfgspace_t *psc = arg;
+ pcieadm_cfgspace_f readf;
+ void *readarg;
+ char fname[128];
+
+ psc->psc_pci->pia_devstr = di_node_name(devi);
+ psc->psc_pci->pia_devi = devi;
+ psc->psc_pci->pia_nexus = DI_NODE_NIL;
+ pcieadm_find_nexus(psc->psc_pci);
+ if (psc->psc_pci->pia_nexus == DI_NODE_NIL) {
+ warnx("failed to find nexus for %s", di_node_name(devi));
+ psc->psc_ret = EXIT_FAILURE;
+ return (DI_WALK_CONTINUE);
+ }
+
+ nregs = di_prop_lookup_ints(DDI_DEV_T_ANY, devi, "reg", &regs);
+ if (nregs <= 0) {
+ warnx("failed to lookup regs array for %s",
+ psc->psc_pci->pia_devstr);
+ psc->psc_ret = EXIT_FAILURE;
+ return (DI_WALK_CONTINUE);
+ }
+
+ (void) snprintf(fname, sizeof (fname), "%02x-%02x-%02x.pci",
+ PCI_REG_BUS_G(regs[0]), PCI_REG_DEV_G(regs[0]),
+ PCI_REG_FUNC_G(regs[0]));
+
+ if ((fd = openat(psc->psc_dirfd, fname, O_WRONLY | O_TRUNC | O_CREAT,
+ 0666)) < 0) {
+ warn("failed to create output file %s", fname);
+ psc->psc_ret = EXIT_FAILURE;
+ return (DI_WALK_CONTINUE);
+ }
+
+ pcieadm_init_cfgspace_kernel(psc->psc_pci, &readf, &readarg);
+ pcieadm_cfgspace(psc->psc_pci, PCIEADM_CFGSPACE_OP_WRITE, readf, fd,
+ readarg, 0, NULL, 0, NULL);
+ pcieadm_fini_cfgspace_kernel(readarg);
+
+ if (close(fd) != 0) {
+ warn("failed to close output fd for %s", fname);
+ psc->psc_ret = EXIT_FAILURE;
+ } else {
+ psc->psc_nsaved++;
+ }
+
+ return (DI_WALK_CONTINUE);
+}
+
+void
+pcieadm_save_cfgspace_usage(FILE *f)
+{
+ (void) fprintf(f, "\tsave-devs\t-d device output-file\n");
+ (void) fprintf(f, "\tsave-devs\t-a output-directory\n");
+}
+
+static void
+pcieadm_save_cfgspace_help(const char *fmt, ...)
+{
+ if (fmt != NULL) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ vwarnx(fmt, ap);
+ va_end(ap);
+ (void) fprintf(stderr, "\n");
+ }
+
+ (void) fprintf(stderr, "Usage: %s save-cfgspace -d device "
+ "output-file\n", pcieadm_progname);
+ (void) fprintf(stderr, " %s save-cfgspace -a "
+ "output-directory\n", pcieadm_progname);
+
+ (void) fprintf(stderr, "\nSave PCI configuration space data from a "
+ "device to a file or\nsave all devices to a specified directory."
+ "\n\n"
+ "\t-a\t\tsave data from all devices\n"
+ "\t-d device\tread data from the specified device (driver instance,"
+ "\n\t\t\t/devices path, or b/d/f)\n");
+}
+
+int
+pcieadm_save_cfgspace(pcieadm_t *pcip, int argc, char *argv[])
+{
+ int c;
+ pcieadm_cfgspace_f readf;
+ void *readarg;
+ const char *device = NULL;
+ boolean_t do_all = B_FALSE;
+
+ while ((c = getopt(argc, argv, ":ad:")) != -1) {
+ switch (c) {
+ case 'a':
+ do_all = B_TRUE;
+ break;
+ case 'd':
+ device = optarg;
+ break;
+ case ':':
+ pcieadm_save_cfgspace_help("Option -%c requires an "
+ "argument", optopt);
+ exit(EXIT_USAGE);
+ case '?':
+ default:
+ pcieadm_save_cfgspace_help("unknown option: -%c",
+ optopt);
+ exit(EXIT_USAGE);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (device == NULL && !do_all) {
+ pcieadm_save_cfgspace_help("missing required -d option to "
+ "indicate device to dump");
+ exit(EXIT_USAGE);
+ }
+
+ if (argc != 1) {
+ pcieadm_save_cfgspace_help("missing required output path");
+ exit(EXIT_USAGE);
+ }
+
+ /*
+ * For reading from devices, we need to full privileges, unfortunately.
+ */
+ priv_fillset(pcip->pia_priv_eff);
+ pcieadm_init_privs(pcip);
+
+ if (!do_all) {
+ int fd;
+
+ pcieadm_find_dip(pcip, device);
+
+ if (setppriv(PRIV_SET, PRIV_EFFECTIVE, pcip->pia_priv_eff) !=
+ 0) {
+ err(EXIT_FAILURE, "failed to raise privileges");
+ }
+
+ if ((fd = open(argv[0], O_WRONLY | O_CREAT | O_TRUNC, 0666)) <
+ 0) {
+ err(EXIT_FAILURE, "failed to open output file %s",
+ argv[0]);
+ }
+
+ if (setppriv(PRIV_SET, PRIV_EFFECTIVE, pcip->pia_priv_min) !=
+ 0) {
+ err(EXIT_FAILURE, "failed to reduce privileges");
+ }
+
+ pcieadm_init_cfgspace_kernel(pcip, &readf, &readarg);
+ pcieadm_cfgspace(pcip, PCIEADM_CFGSPACE_OP_WRITE, readf, fd,
+ readarg, 0, NULL, 0, NULL);
+ pcieadm_fini_cfgspace_kernel(readarg);
+
+ if (close(fd) != 0) {
+ err(EXIT_FAILURE, "failed to close output file "
+ "descriptor");
+ }
+
+ return (EXIT_SUCCESS);
+ } else {
+ pcieadm_save_cfgspace_t psc;
+ pcieadm_di_walk_t walk;
+
+ if (setppriv(PRIV_SET, PRIV_EFFECTIVE, pcip->pia_priv_eff) !=
+ 0) {
+ err(EXIT_FAILURE, "failed to raise privileges");
+ }
+
+ if ((psc.psc_dirfd = open(argv[0], O_RDONLY | O_DIRECTORY)) <
+ 0) {
+ err(EXIT_FAILURE, "failed to open output directory %s",
+ argv[0]);
+ }
+
+ if (setppriv(PRIV_SET, PRIV_EFFECTIVE, pcip->pia_priv_min) !=
+ 0) {
+ err(EXIT_FAILURE, "failed to reduce privileges");
+ }
+
+ psc.psc_nsaved = 0;
+ psc.psc_ret = EXIT_SUCCESS;
+ psc.psc_pci = pcip;
+
+ walk.pdw_arg = &psc;
+ walk.pdw_func = pcieadm_save_cfgspace_cb;
+ pcieadm_di_walk(pcip, &walk);
+
+ VERIFY0(close(psc.psc_dirfd));
+
+ if (psc.psc_nsaved == 0) {
+ warnx("failed to save any PCI devices");
+ return (EXIT_FAILURE);
+ }
+
+ pcieadm_print("successfully saved %u devices to %s\n",
+ psc.psc_nsaved, argv[0]);
+ return (psc.psc_ret);
+ }
+}
diff --git a/usr/src/cmd/pcieadm/pcieadm_devs.c b/usr/src/cmd/pcieadm/pcieadm_devs.c
new file mode 100644
index 0000000000..5ca19ea1d9
--- /dev/null
+++ b/usr/src/cmd/pcieadm/pcieadm_devs.c
@@ -0,0 +1,568 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2021 Oxide Computer Company
+ */
+
+#include <err.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <ofmt.h>
+#include <strings.h>
+#include <sys/pci.h>
+
+#include "pcieadm.h"
+
+typedef struct pcieadm_show_devs {
+ pcieadm_t *psd_pia;
+ ofmt_handle_t psd_ofmt;
+ boolean_t psd_funcs;
+ int psd_nfilts;
+ char **psd_filts;
+ uint_t psd_nprint;
+} pcieadm_show_devs_t;
+
+typedef enum pcieadm_show_devs_otype {
+ PCIEADM_SDO_VID,
+ PCIEADM_SDO_DID,
+ PCIEADM_SDO_BDF,
+ PCIEADM_SDO_BDF_BUS,
+ PCIEADM_SDO_BDF_DEV,
+ PCIEADM_SDO_BDF_FUNC,
+ PCIEADM_SDO_DRIVER,
+ PCIEADM_SDO_TYPE,
+ PCIEADM_SDO_VENDOR,
+ PCIEADM_SDO_DEVICE,
+ PCIEADM_SDO_PATH,
+ PCIEADM_SDO_MAXSPEED,
+ PCIEADM_SDO_MAXWIDTH,
+ PCIEADM_SDO_CURSPEED,
+ PCIEADM_SDO_CURWIDTH,
+ PCIEADM_SDO_SUPSPEEDS
+} pcieadm_show_devs_otype_t;
+
+typedef struct pcieadm_show_devs_ofmt {
+ int psdo_vid;
+ int psdo_did;
+ uint_t psdo_bus;
+ uint_t psdo_dev;
+ uint_t psdo_func;
+ const char *psdo_path;
+ const char *psdo_vendor;
+ const char *psdo_device;
+ const char *psdo_driver;
+ int psdo_instance;
+ int psdo_mwidth;
+ int psdo_cwidth;
+ int64_t psdo_mspeed;
+ int64_t psdo_cspeed;
+ int psdo_nspeeds;
+ int64_t *psdo_sspeeds;
+} pcieadm_show_devs_ofmt_t;
+
+static uint_t
+pcieadm_speed2gen(int64_t speed)
+{
+ if (speed == 2500000000LL) {
+ return (1);
+ } else if (speed == 5000000000LL) {
+ return (2);
+ } else if (speed == 8000000000LL) {
+ return (3);
+ } else if (speed == 16000000000LL) {
+ return (4);
+ } else if (speed == 32000000000LL) {
+ return (5);
+ } else {
+ return (0);
+ }
+}
+
+static const char *
+pcieadm_speed2str(int64_t speed)
+{
+ if (speed == 2500000000LL) {
+ return ("2.5");
+ } else if (speed == 5000000000LL) {
+ return ("5.0");
+ } else if (speed == 8000000000LL) {
+ return ("8.0");
+ } else if (speed == 16000000000LL) {
+ return ("16.0");
+ } else if (speed == 32000000000LL) {
+ return ("32.0");
+ } else {
+ return (NULL);
+ }
+}
+
+static boolean_t
+pcieadm_show_devs_ofmt_cb(ofmt_arg_t *ofarg, char *buf, uint_t buflen)
+{
+ const char *str;
+ pcieadm_show_devs_ofmt_t *psdo = ofarg->ofmt_cbarg;
+ boolean_t first = B_TRUE;
+
+ switch (ofarg->ofmt_id) {
+ case PCIEADM_SDO_BDF:
+ if (snprintf(buf, buflen, "%x/%x/%x", psdo->psdo_bus,
+ psdo->psdo_dev, psdo->psdo_func) >= buflen) {
+ return (B_FALSE);
+ }
+ break;
+ case PCIEADM_SDO_BDF_BUS:
+ if (snprintf(buf, buflen, "%x", psdo->psdo_bus) >= buflen) {
+ return (B_FALSE);
+ }
+ break;
+ case PCIEADM_SDO_BDF_DEV:
+ if (snprintf(buf, buflen, "%x", psdo->psdo_dev) >= buflen) {
+ return (B_FALSE);
+ }
+ break;
+ case PCIEADM_SDO_BDF_FUNC:
+ if (snprintf(buf, buflen, "%x", psdo->psdo_func) >= buflen) {
+ return (B_FALSE);
+ }
+ break;
+ case PCIEADM_SDO_DRIVER:
+ if (psdo->psdo_driver == NULL || psdo->psdo_instance == -1) {
+ (void) snprintf(buf, buflen, "--");
+ } else if (snprintf(buf, buflen, "%s%d", psdo->psdo_driver,
+ psdo->psdo_instance) >= buflen) {
+ return (B_FALSE);
+ }
+ break;
+ case PCIEADM_SDO_PATH:
+ if (strlcat(buf, psdo->psdo_path, buflen) >= buflen) {
+ return (B_TRUE);
+ }
+ break;
+ case PCIEADM_SDO_VID:
+ if (psdo->psdo_vid == -1) {
+ (void) strlcat(buf, "--", buflen);
+ } else if (snprintf(buf, buflen, "%x", psdo->psdo_vid) >=
+ buflen) {
+ return (B_FALSE);
+ }
+ break;
+ case PCIEADM_SDO_DID:
+ if (psdo->psdo_did == -1) {
+ (void) strlcat(buf, "--", buflen);
+ } else if (snprintf(buf, buflen, "%x", psdo->psdo_did) >=
+ buflen) {
+ return (B_FALSE);
+ }
+ break;
+ case PCIEADM_SDO_VENDOR:
+ if (strlcat(buf, psdo->psdo_vendor, buflen) >= buflen) {
+ return (B_FALSE);
+ }
+ break;
+ case PCIEADM_SDO_DEVICE:
+ if (strlcat(buf, psdo->psdo_device, buflen) >= buflen) {
+ return (B_FALSE);
+ }
+ break;
+ case PCIEADM_SDO_MAXWIDTH:
+ if (psdo->psdo_mwidth <= 0) {
+ (void) strlcat(buf, "--", buflen);
+ } else if (snprintf(buf, buflen, "x%u", psdo->psdo_mwidth) >=
+ buflen) {
+ return (B_FALSE);
+ }
+ break;
+ case PCIEADM_SDO_CURWIDTH:
+ if (psdo->psdo_cwidth <= 0) {
+ (void) strlcat(buf, "--", buflen);
+ } else if (snprintf(buf, buflen, "x%u", psdo->psdo_cwidth) >=
+ buflen) {
+ return (B_FALSE);
+ }
+ break;
+ case PCIEADM_SDO_MAXSPEED:
+ str = pcieadm_speed2str(psdo->psdo_mspeed);
+ if (str == NULL) {
+ (void) strlcat(buf, "--", buflen);
+ } else if (snprintf(buf, buflen, "%s GT/s", str) >= buflen) {
+ return (B_FALSE);
+ }
+ break;
+ case PCIEADM_SDO_CURSPEED:
+ str = pcieadm_speed2str(psdo->psdo_cspeed);
+ if (str == NULL) {
+ (void) strlcat(buf, "--", buflen);
+ } else if (snprintf(buf, buflen, "%s GT/s", str) >= buflen) {
+ return (B_FALSE);
+ }
+ break;
+ case PCIEADM_SDO_SUPSPEEDS:
+ buf[0] = 0;
+ for (int i = 0; i < psdo->psdo_nspeeds; i++) {
+ const char *str;
+
+ str = pcieadm_speed2str(psdo->psdo_sspeeds[i]);
+ if (str == NULL) {
+ continue;
+ }
+
+ if (!first) {
+ if (strlcat(buf, ",", buflen) >= buflen) {
+ return (B_FALSE);
+ }
+ }
+ first = B_FALSE;
+
+ if (strlcat(buf, str, buflen) >= buflen) {
+ return (B_FALSE);
+ }
+ }
+ break;
+ case PCIEADM_SDO_TYPE:
+ if (pcieadm_speed2gen(psdo->psdo_mspeed) == 0 ||
+ psdo->psdo_mwidth == -1) {
+ if (strlcat(buf, "PCI", buflen) >= buflen) {
+ return (B_FALSE);
+ }
+ } else {
+ if (snprintf(buf, buflen, "PCIe Gen %ux%u",
+ pcieadm_speed2gen(psdo->psdo_mspeed),
+ psdo->psdo_mwidth) >= buflen) {
+ return (B_FALSE);
+ }
+ }
+ break;
+ default:
+ abort();
+ }
+ return (B_TRUE);
+}
+
+static const char *pcieadm_show_dev_fields = "bdf,type,driver,device";
+static const char *pcieadm_show_dev_speeds =
+ "bdf,driver,maxspeed,curspeed,maxwidth,curwidth,supspeeds";
+static const ofmt_field_t pcieadm_show_dev_ofmt[] = {
+ { "VID", 6, PCIEADM_SDO_VID, pcieadm_show_devs_ofmt_cb },
+ { "DID", 6, PCIEADM_SDO_DID, pcieadm_show_devs_ofmt_cb },
+ { "BDF", 8, PCIEADM_SDO_BDF, pcieadm_show_devs_ofmt_cb },
+ { "DRIVER", 15, PCIEADM_SDO_DRIVER, pcieadm_show_devs_ofmt_cb },
+ { "TYPE", 15, PCIEADM_SDO_TYPE, pcieadm_show_devs_ofmt_cb },
+ { "VENDOR", 30, PCIEADM_SDO_VENDOR, pcieadm_show_devs_ofmt_cb },
+ { "DEVICE", 30, PCIEADM_SDO_DEVICE, pcieadm_show_devs_ofmt_cb },
+ { "PATH", 30, PCIEADM_SDO_PATH, pcieadm_show_devs_ofmt_cb },
+ { "BUS", 4, PCIEADM_SDO_BDF_BUS, pcieadm_show_devs_ofmt_cb },
+ { "DEV", 4, PCIEADM_SDO_BDF_DEV, pcieadm_show_devs_ofmt_cb },
+ { "FUNC", 4, PCIEADM_SDO_BDF_FUNC, pcieadm_show_devs_ofmt_cb },
+ { "MAXSPEED", 10, PCIEADM_SDO_MAXSPEED, pcieadm_show_devs_ofmt_cb },
+ { "MAXWIDTH", 10, PCIEADM_SDO_MAXWIDTH, pcieadm_show_devs_ofmt_cb },
+ { "CURSPEED", 10, PCIEADM_SDO_CURSPEED, pcieadm_show_devs_ofmt_cb },
+ { "CURWIDTH", 10, PCIEADM_SDO_CURWIDTH, pcieadm_show_devs_ofmt_cb },
+ { "SUPSPEEDS", 20, PCIEADM_SDO_SUPSPEEDS, pcieadm_show_devs_ofmt_cb },
+ { NULL, 0, 0, NULL }
+};
+
+static boolean_t
+pcieadm_show_devs_match(pcieadm_show_devs_t *psd,
+ pcieadm_show_devs_ofmt_t *psdo)
+{
+ char dinst[128], bdf[128];
+
+ if (psd->psd_nfilts == 0) {
+ return (B_TRUE);
+ }
+
+ if (psdo->psdo_driver != NULL && psdo->psdo_instance != -1) {
+ (void) snprintf(dinst, sizeof (dinst), "%s%d",
+ psdo->psdo_driver, psdo->psdo_instance);
+ }
+ (void) snprintf(bdf, sizeof (bdf), "%x/%x/%x", psdo->psdo_bus,
+ psdo->psdo_dev, psdo->psdo_func);
+
+ for (uint_t i = 0; i < psd->psd_nfilts; i++) {
+ const char *filt = psd->psd_filts[i];
+
+ if (strcmp(filt, psdo->psdo_path) == 0) {
+ return (B_TRUE);
+ }
+
+ if (strcmp(filt, bdf) == 0) {
+ return (B_TRUE);
+ }
+
+ if (psdo->psdo_driver != NULL &&
+ strcmp(filt, psdo->psdo_driver) == 0) {
+ return (B_TRUE);
+ }
+
+ if (psdo->psdo_driver != NULL && psdo->psdo_instance != -1 &&
+ strcmp(filt, dinst) == 0) {
+ return (B_TRUE);
+ }
+
+ if (strncmp("/devices", filt, strlen("/devices")) == 0) {
+ filt += strlen("/devices");
+ }
+
+ if (strcmp(filt, psdo->psdo_path) == 0) {
+ return (B_TRUE);
+ }
+ }
+ return (B_FALSE);
+}
+
+static int
+pcieadm_show_devs_walk_cb(di_node_t node, void *arg)
+{
+ int nprop, *regs = NULL, *did, *vid, *mwidth, *cwidth;
+ int64_t *mspeed, *cspeed, *sspeeds;
+ char *path = NULL;
+ pcieadm_show_devs_t *psd = arg;
+ int ret = DI_WALK_CONTINUE;
+ pcieadm_show_devs_ofmt_t oarg;
+ pcidb_hdl_t *pcidb = psd->psd_pia->pia_pcidb;
+
+ bzero(&oarg, sizeof (oarg));
+
+ path = di_devfs_path(node);
+ if (path == NULL) {
+ err(EXIT_FAILURE, "failed to construct devfs path for node: "
+ "%s (%s)", di_node_name(node));
+ }
+
+ nprop = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", &regs);
+ if (nprop <= 0) {
+ errx(EXIT_FAILURE, "failed to lookup regs array for %s",
+ path);
+ }
+
+ oarg.psdo_path = path;
+ oarg.psdo_bus = PCI_REG_BUS_G(regs[0]);
+ oarg.psdo_dev = PCI_REG_DEV_G(regs[0]);
+ oarg.psdo_func = PCI_REG_FUNC_G(regs[0]);
+
+ if (oarg.psdo_func != 0 && !psd->psd_funcs) {
+ goto done;
+ }
+
+ oarg.psdo_driver = di_driver_name(node);
+ oarg.psdo_instance = di_instance(node);
+
+ nprop = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "device-id", &did);
+ if (nprop != 1) {
+ oarg.psdo_did = -1;
+ } else {
+ oarg.psdo_did = (uint16_t)*did;
+ }
+
+ nprop = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "vendor-id", &vid);
+ if (nprop != 1) {
+ oarg.psdo_vid = -1;
+ } else {
+ oarg.psdo_vid = (uint16_t)*vid;
+ }
+
+ oarg.psdo_vendor = "--";
+ if (oarg.psdo_vid != -1) {
+ pcidb_vendor_t *vend = pcidb_lookup_vendor(pcidb,
+ oarg.psdo_vid);
+ if (vend != NULL) {
+ oarg.psdo_vendor = pcidb_vendor_name(vend);
+ }
+ }
+
+ oarg.psdo_device = "--";
+ if (oarg.psdo_vid != -1 && oarg.psdo_did != -1) {
+ pcidb_device_t *dev = pcidb_lookup_device(pcidb,
+ oarg.psdo_vid, oarg.psdo_did);
+ if (dev != NULL) {
+ oarg.psdo_device = pcidb_device_name(dev);
+
+ }
+ }
+
+ nprop = di_prop_lookup_ints(DDI_DEV_T_ANY, node,
+ "pcie-link-maximum-width", &mwidth);
+ if (nprop != 1) {
+ oarg.psdo_mwidth = -1;
+ } else {
+ oarg.psdo_mwidth = *mwidth;
+ }
+
+ nprop = di_prop_lookup_ints(DDI_DEV_T_ANY, node,
+ "pcie-link-current-width", &cwidth);
+ if (nprop != 1) {
+ oarg.psdo_cwidth = -1;
+ } else {
+ oarg.psdo_cwidth = *cwidth;
+ }
+
+ nprop = di_prop_lookup_int64(DDI_DEV_T_ANY, node,
+ "pcie-link-maximum-speed", &mspeed);
+ if (nprop != 1) {
+ oarg.psdo_mspeed = -1;
+ } else {
+ oarg.psdo_mspeed = *mspeed;
+ }
+
+ nprop = di_prop_lookup_int64(DDI_DEV_T_ANY, node,
+ "pcie-link-current-speed", &cspeed);
+ if (nprop != 1) {
+ oarg.psdo_cspeed = -1;
+ } else {
+ oarg.psdo_cspeed = *cspeed;
+ }
+
+ nprop = di_prop_lookup_int64(DDI_DEV_T_ANY, node,
+ "pcie-link-supported-speeds", &sspeeds);
+ if (nprop > 0) {
+ oarg.psdo_nspeeds = nprop;
+ oarg.psdo_sspeeds = sspeeds;
+ } else {
+ oarg.psdo_nspeeds = 0;
+ oarg.psdo_sspeeds = NULL;
+ }
+
+ if (pcieadm_show_devs_match(psd, &oarg)) {
+ ofmt_print(psd->psd_ofmt, &oarg);
+ psd->psd_nprint++;
+ }
+
+done:
+ if (path != NULL) {
+ di_devfs_path_free(path);
+ }
+
+ return (ret);
+}
+
+void
+pcieadm_show_devs_usage(FILE *f)
+{
+ (void) fprintf(f, "\tshow-devs\t[-F] [-H] [-s | -o field[,...] [-p]] "
+ "[filter...]\n");
+}
+
+static void
+pcieadm_show_devs_help(const char *fmt, ...)
+{
+ if (fmt != NULL) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ vwarnx(fmt, ap);
+ va_end(ap);
+ (void) fprintf(stderr, "\n");
+ }
+
+ (void) fprintf(stderr, "Usage: %s show-devs [-F] [-H] [-s | -o "
+ "field[,...] [-p]] [filter...]\n", pcieadm_progname);
+
+ (void) fprintf(stderr, "\nList PCI devices and functions in the "
+ "system. Each <filter> selects a set\nof devices to show and "
+ "can be a driver name, instance, /devices path, or\nb/d/f.\n\n"
+ "\t-F\t\tdo not display PCI functions\n"
+ "\t-H\t\tomit the column header\n"
+ "\t-o field\toutput fields to print\n"
+ "\t-p\t\tparsable output (requires -o)\n"
+ "\t-s\t\tlist speeds and widths\n");
+
+}
+
+int
+pcieadm_show_devs(pcieadm_t *pcip, int argc, char *argv[])
+{
+ int c;
+ uint_t flags = 0;
+ const char *fields = NULL;
+ pcieadm_show_devs_t psd;
+ pcieadm_di_walk_t walk;
+ ofmt_status_t oferr;
+ boolean_t parse = B_FALSE;
+ boolean_t speeds = B_FALSE;
+
+ /*
+ * show-devs relies solely on the devinfo snapshot we already took.
+ * Formalize our privs immediately.
+ */
+ pcieadm_init_privs(pcip);
+
+ bzero(&psd, sizeof (psd));
+ psd.psd_pia = pcip;
+ psd.psd_funcs = B_TRUE;
+
+ while ((c = getopt(argc, argv, ":FHo:ps")) != -1) {
+ switch (c) {
+ case 'F':
+ psd.psd_funcs = B_FALSE;
+ break;
+ case 'p':
+ parse = B_TRUE;
+ flags |= OFMT_PARSABLE;
+ break;
+ case 'H':
+ flags |= OFMT_NOHEADER;
+ break;
+ case 's':
+ speeds = B_TRUE;
+ break;
+ case 'o':
+ fields = optarg;
+ break;
+ case ':':
+ pcieadm_show_devs_help("option -%c requires an "
+ "argument", optopt);
+ exit(EXIT_USAGE);
+ case '?':
+ pcieadm_show_devs_help("unknown option: -%c", optopt);
+ exit(EXIT_USAGE);
+ }
+ }
+
+ if (parse && fields == NULL) {
+ errx(EXIT_USAGE, "-p requires fields specified with -o");
+ }
+
+ if (fields != NULL && speeds) {
+ errx(EXIT_USAGE, "-s cannot be used with with -o");
+ }
+
+ if (fields == NULL) {
+ if (speeds) {
+ fields = pcieadm_show_dev_speeds;
+ } else {
+ fields = pcieadm_show_dev_fields;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 0) {
+ psd.psd_nfilts = argc;
+ psd.psd_filts = argv;
+ }
+
+ oferr = ofmt_open(fields, pcieadm_show_dev_ofmt, flags, 0,
+ &psd.psd_ofmt);
+ ofmt_check(oferr, parse, psd.psd_ofmt, pcieadm_ofmt_errx, warnx);
+
+ walk.pdw_arg = &psd;
+ walk.pdw_func = pcieadm_show_devs_walk_cb;
+
+ pcieadm_di_walk(pcip, &walk);
+
+ if (psd.psd_nprint > 0) {
+ return (EXIT_SUCCESS);
+ } else {
+ return (EXIT_FAILURE);
+ }
+}
diff --git a/usr/src/cmd/sendmail/src/daemon.c b/usr/src/cmd/sendmail/src/daemon.c
index 983ad2fe3e..b048fc8ecf 100644
--- a/usr/src/cmd/sendmail/src/daemon.c
+++ b/usr/src/cmd/sendmail/src/daemon.c
@@ -4360,10 +4360,11 @@ anynet_ntoa(sap)
(void) sm_snprintf(buf, sizeof(buf), "Family %d: ", sap->sa.sa_family);
bp = &buf[strlen(buf)];
ap = sap->sa.sa_data;
- for (l = sizeof(sap->sa.sa_data); --l >= 0; )
+ for (l = sizeof(sap->sa.sa_data); --l >= 0 && SPACELEFT(buf, bp) > 3; )
{
(void) sm_snprintf(bp, SPACELEFT(buf, bp), "%02x:",
*ap++ & 0377);
+
bp += 3;
}
*--bp = '\0';
diff --git a/usr/src/cmd/sgs/elfdump/Makefile.com b/usr/src/cmd/sgs/elfdump/Makefile.com
index 59a1e75556..085591a246 100644
--- a/usr/src/cmd/sgs/elfdump/Makefile.com
+++ b/usr/src/cmd/sgs/elfdump/Makefile.com
@@ -57,7 +57,7 @@ LDFLAGS += $(VERSREF) $(MAPOPT) $(LLDFLAGS)
LDLIBS += $(ELFLIBDIR) -lelf $(LDDBGLIBDIR) -llddbg \
$(CONVLIBDIR) -lconv
-NATIVE_LDFLAGS = $(LDASSERTS) $(BDIRECT) $(ZASSERTDEFLIB)=libc.so
+NATIVE_LDFLAGS = $(LDASSERTS) $(BDIRECT)
CERRWARN += $(CNOWARN_UNINIT)
diff --git a/usr/src/cmd/sgs/libld/common/syms.c b/usr/src/cmd/sgs/libld/common/syms.c
index a40f8ae5cd..ff073c9aa7 100644
--- a/usr/src/cmd/sgs/libld/common/syms.c
+++ b/usr/src/cmd/sgs/libld/common/syms.c
@@ -1718,8 +1718,9 @@ ld_sym_validate(Ofl_desc *ofl)
sym->st_name) && (st_insert(ofl->ofl_strtab,
sdp->sd_name) == -1))
return (S_ERROR);
- if (allow_ldynsym && sym->st_name &&
- ldynsym_symtype[type]) {
+ if (allow_ldynsym && ldynsym_symtype[type] &&
+ ((sym->st_name != 0) ||
+ (type == STT_FILE))) {
ofl->ofl_dynscopecnt++;
if (st_insert(ofl->ofl_dynstrtab,
sdp->sd_name) == -1)
@@ -2452,8 +2453,14 @@ ld_sym_process(Is_desc *isc, Ifl_desc *ifl, Ofl_desc *ofl)
sdp->sd_name) == -1))
return (S_ERROR);
- if (allow_ldynsym && sym->st_name &&
- ldynsym_symtype[type]) {
+ /*
+ * STT_FILE symbols must always remain, to
+ * maintain the ordering semantics of symbol
+ * tables.
+ */
+ if (allow_ldynsym && ldynsym_symtype[type] &&
+ ((sym->st_name != 0) ||
+ (type == STT_FILE))) {
ofl->ofl_dynlocscnt++;
if (st_insert(ofl->ofl_dynstrtab,
sdp->sd_name) == -1)
diff --git a/usr/src/cmd/sgs/libld/common/update.c b/usr/src/cmd/sgs/libld/common/update.c
index d61d4cfcd5..8ef1be8343 100644
--- a/usr/src/cmd/sgs/libld/common/update.c
+++ b/usr/src/cmd/sgs/libld/common/update.c
@@ -702,9 +702,11 @@ update_osym(Ofl_desc *ofl)
enter_in_symtab = symtab &&
(!(ofl->ofl_flags & FLG_OF_REDLSYM) ||
sdp->sd_move);
- enter_in_ldynsym = ldynsym && sdp->sd_name &&
+ enter_in_ldynsym = ldynsym &&
+ ((sym->st_name != 0) || (type == STT_FILE)) &&
ldynsym_symtype[type] &&
!(ofl->ofl_flags & FLG_OF_REDLSYM);
+
_symshndx = NULL;
if (enter_in_symtab) {
diff --git a/usr/src/cmd/sgs/tools/Makefile.com b/usr/src/cmd/sgs/tools/Makefile.com
index 634fec820a..9d1c34949c 100644
--- a/usr/src/cmd/sgs/tools/Makefile.com
+++ b/usr/src/cmd/sgs/tools/Makefile.com
@@ -42,7 +42,7 @@ include $(SRC)/cmd/sgs/Makefile.com
OBJECTS= piglatin.o
NATIVECC_CFLAGS = -O
-NATIVE_LDFLAGS = $(LDASSERTS) $(ZASSERTDEFLIB)=libc.so $(BDIRECT)
+NATIVE_LDFLAGS = $(LDASSERTS) $(BDIRECT)
NATIVE= $(OBJECTS:%.o=%)
SRCS= $(OBJECTS:%.o=../common/%.c)
diff --git a/usr/src/cmd/sgs/tools/SUNWonld-README b/usr/src/cmd/sgs/tools/SUNWonld-README
index a414a6bfe8..d29de0aa81 100644
--- a/usr/src/cmd/sgs/tools/SUNWonld-README
+++ b/usr/src/cmd/sgs/tools/SUNWonld-README
@@ -1670,3 +1670,4 @@ Bugid Risk Synopsis
11057 hidden undefined weak symbols should not leave relocations
11067 debug statistics crash ld(1) when -z allextract
13481 ld(1) should skip GCC local aliases when building symsort sections
+13684 ld aborts when input object has no file name
diff --git a/usr/src/contrib/mDNSResponder/Clients/dns-sd.c b/usr/src/contrib/mDNSResponder/Clients/dns-sd.c
index b9fe853ce8..3a3cc0d82a 100644
--- a/usr/src/contrib/mDNSResponder/Clients/dns-sd.c
+++ b/usr/src/contrib/mDNSResponder/Clients/dns-sd.c
@@ -1,6 +1,6 @@
/* -*- Mode: C; tab-width: 4 -*-
*
- * Copyright (c) 2002-2015 Apple Inc. All rights reserved.
+ * Copyright (c) 2002-2020 Apple Inc. All rights reserved.
*
* Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc.
* ("Apple") in consideration of your agreement to the following terms, and your
@@ -64,6 +64,14 @@
#include <errno.h> // For errno, EINTR
#include <time.h>
#include <sys/types.h> // For u_char
+#ifdef APPLE_OSX_mDNSResponder
+#include <inttypes.h> // For PRId64
+#endif // APPLE_OSX_mDNSResponder
+
+#if APPLE_OSX_mDNSResponder
+#include <xpc/xpc.h>
+#include "xpc_clients.h"
+#endif
#ifdef _WIN32
#include <winsock2.h>
@@ -165,8 +173,10 @@ static const char kFilePathSep = '/';
#undef _DNS_SD_LIBDISPATCH
#endif
#include "dns_sd.h"
-#include "dns_sd_internal.h"
+#include "dns_sd_private.h"
#include "ClientCommon.h"
+#include <stdarg.h>
+
#if TEST_NEW_CLIENTSTUB
#include "../mDNSShared/dnssd_ipc.c"
@@ -174,6 +184,9 @@ static const char kFilePathSep = '/';
#include "../mDNSShared/dnssd_clientstub.c"
#endif
+#ifndef MIN
+#define MIN(x, y) ((x) < (y) ? (x) : (y))
+#endif
//*************************************************************************************************************
// Globals
@@ -309,6 +322,8 @@ static uint16_t GetRRType(const char *s)
else if (!strcasecmp(s, "ds" )) return(kDNSServiceType_DS);
else if (!strcasecmp(s, "rrsig" )) return(kDNSServiceType_RRSIG);
else if (!strcasecmp(s, "nsec" )) return(kDNSServiceType_NSEC);
+ else if (!strcasecmp(s, "SVCB" )) return(kDNSServiceType_SVCB);
+ else if (!strcasecmp(s, "HTTPS" )) return(kDNSServiceType_HTTPS);
else if (!strcasecmp(s, "ANY" )) return(kDNSServiceType_ANY);
else return(atoi(s));
}
@@ -380,6 +395,8 @@ static char *DNSTypeName(unsigned short rr_type)
case kDNSServiceType_AXFR: return("AXFR");
case kDNSServiceType_MAILB: return("MAILB");
case kDNSServiceType_MAILA: return("MAILA");
+ case kDNSServiceType_SVCB: return("SVCB");
+ case kDNSServiceType_HTTPS: return("HTTPS");
case kDNSServiceType_ANY: return("ANY");
default:
{
@@ -509,49 +526,50 @@ static void FormatTime(unsigned long te, unsigned char *buf, int bufsize)
static void print_usage(const char *arg0, int print_all)
{
// Print the commonly used command line options. These are listed in "the order they have been in historically".
- fprintf(stderr, "%s -E (Enumerate recommended registration domains)\n", arg0);
- fprintf(stderr, "%s -F (Enumerate recommended browsing domains)\n", arg0);
- fprintf(stderr, "%s -R <Name> <Type> <Domain> <Port> [<TXT>...] (Register a service)\n", arg0);
- fprintf(stderr, "%s -B <Type> <Domain> (Browse for service instances)\n", arg0);
- fprintf(stderr, "%s -L <Name> <Type> <Domain> (Resolve a service instance)\n", arg0);
- fprintf(stderr, "%s -Q <name> <rrtype> <rrclass> (Generic query for any record type)\n", arg0);
- fprintf(stderr, "%s -Z <Type> <Domain> (Output results in Zone File format)\n", arg0);
- fprintf(stderr, "%s -G v4/v6/v4v6 <name> (Get address information for hostname)\n", arg0);
- fprintf(stderr, "%s -H (Print usage for complete command list)\n", arg0);
- fprintf(stderr, "%s -V (Get version of currently running daemon / system service)\n", arg0);
+ fprintf(stderr, "%s -E (Enumerate recommended registration domains)\n", arg0);
+ fprintf(stderr, "%s -F (Enumerate recommended browsing domains)\n", arg0);
+ fprintf(stderr, "%s -R <Name> <Type> <Domain> <Port> [<TXT>...] (Register a service)\n", arg0);
+ fprintf(stderr, "%s -P <Name> <Type> <Domain> <Port> <Host> <IP> [<TXT>...] (Register Proxy)\n", arg0);
+ fprintf(stderr, "%s -B <Type> <Domain> (Browse for service instances)\n", arg0);
+ fprintf(stderr, "%s -Z <Type> <Domain> (Output results in Zone File format)\n", arg0);
+ fprintf(stderr, "%s -L <Name> <Type> <Domain> (Resolve (‘lookup’) a service instance)\n", arg0);
+ fprintf(stderr, "%s -Q <name> <rrtype> <rrclass> (Generic query for any record type)\n", arg0);
+ fprintf(stderr, "%s -q <name> <rrtype> <rrclass> (Generic query, using SuppressUnusable)\n", arg0);
+ fprintf(stderr, "%s -G v4/v6/v4v6 <hostname> (Get address information for hostname)\n", arg0);
+ fprintf(stderr, "%s -X udp/tcp/udptcp <IntPort> <ExtPort> <TTL> (NAT Port Mapping)\n", arg0);
+ fprintf(stderr, "%s -H (Print usage for complete command list)\n", arg0);
+ fprintf(stderr, "%s -V (Get version of currently running daemon / system service)\n", arg0);
+#ifdef APPLE_OSX_mDNSResponder
+ fprintf(stderr, "%s -O [-compress|-stdout](Dump the state of mDNSResponder to file / STDOUT)\n", arg0);
+#endif // APPLE_OSX_mDNSResponder
if (print_all) // Print all available options for dns-sd tool. Keep these in alphabetical order for easier maintenance.
{
fprintf(stderr, "\n");
- fprintf(stderr, "%s -A (Test Adding/Updating/Deleting a record)\n", arg0);
- fprintf(stderr, "%s -C <FQDN> <rrtype> <rrclass> (Query; reconfirming each result)\n", arg0);
- fprintf(stderr, "%s -D <name> <rrtype> <rrclass>(Validate query for any record type with DNSSEC)\n", arg0);
- fprintf(stderr, "%s -I (Test registering and then immediately updating TXT record)\n", arg0);
- fprintf(stderr, "%s -N (Test adding a large NULL record)\n", arg0);
- fprintf(stderr, "%s -M (Test creating a registration with multiple TXT records)\n", arg0);
- fprintf(stderr, "%s -P <Name> <Type> <Domain> <Port> <Host> <IP> [<TXT>...] (Proxy)\n", arg0);
- fprintf(stderr, "%s -S (Test multiple operations on a shared socket)\n", arg0);
- fprintf(stderr, "%s -T (Test creating a large TXT record)\n", arg0);
- fprintf(stderr, "%s -U (Test updating a TXT record)\n", arg0);
- fprintf(stderr, "%s -X udp/tcp/udptcp <IntPort> <ExtPort> <TTL> (NAT Port Mapping)\n", arg0);
- fprintf(stderr, "%s -ble (Use kDNSServiceInterfaceIndexBLE)\n", arg0);
- fprintf(stderr, "%s -g v4/v6/v4v6 <name> (Validate address info for hostname with DNSSEC)\n", arg0);
- fprintf(stderr, "%s -i <Interface> (Run dns-sd cmd on a specific interface (en0/en1)\n", arg0);
- fprintf(stderr, "%s -includep2p (Set kDNSServiceFlagsIncludeP2P flag)\n", arg0);
- fprintf(stderr, "%s -includeAWDL (Set kDNSServiceFlagsIncludeAWDL flag)\n", arg0);
- fprintf(stderr, "%s -intermediates (Set kDNSServiceFlagsReturnIntermediates flag)\n", arg0);
- fprintf(stderr, "%s -ku (Set kDNSServiceFlagsKnownUnique flag)\n", arg0);
- fprintf(stderr, "%s -lo (Run dns-sd cmd using local only interface)\n", arg0);
- fprintf(stderr, "%s -optional (Set kDNSServiceFlagsValidateOptional flag)\n", arg0);
- fprintf(stderr, "%s -p2p (Use kDNSServiceInterfaceIndexP2P)\n", arg0);
- fprintf(stderr, "%s -q <name> <rrtype> <rrclass> (Equivalent to -Q with kDNSServiceFlagsSuppressUnusable set)\n", arg0);
- fprintf(stderr, "%s -tc (Set kDNSServiceFlagsBackgroundTrafficClass flag)\n", arg0);
- fprintf(stderr, "%s -test (Run basic API input range tests)\n", arg0);
- fprintf(stderr, "%s -t1 (Set kDNSServiceFlagsThresholdOne flag)\n", arg0);
- fprintf(stderr, "%s -tFinder (Set kDNSServiceFlagsThresholdFinder flag)\n", arg0);
- fprintf(stderr, "%s -timeout (Set kDNSServiceFlagsTimeout flag)\n", arg0);
- fprintf(stderr, "%s -unicastResponse (Set kDNSServiceFlagsUnicastResponse flag)\n", arg0);
- fprintf(stderr, "%s -autoTrigger (Set kDNSServiceFlagsAutoTrigger flag)\n", arg0);
+ fprintf(stderr, "%s -A (Test Adding/Updating/Deleting a record)\n", arg0);
+ fprintf(stderr, "%s -C <name> <rrtype> <rrclass> (Query; reconfirming each result)\n", arg0);
+ fprintf(stderr, "%s -I (Test registering and then immediately updating TXT record)\n", arg0);
+ fprintf(stderr, "%s -N (Test adding a large NULL record)\n", arg0);
+ fprintf(stderr, "%s -M (Test creating a registration with multiple TXT records)\n", arg0);
+ fprintf(stderr, "%s -S (Test multiple operations on a shared socket)\n", arg0);
+ fprintf(stderr, "%s -T (Test creating a large TXT record)\n", arg0);
+ fprintf(stderr, "%s -U (Test updating a TXT record)\n", arg0);
+ fprintf(stderr, "%s -ble (Use kDNSServiceInterfaceIndexBLE)\n", arg0);
+ fprintf(stderr, "%s -i <Interface> (Run dns-sd cmd on a specific interface (en0/en1)\n", arg0);
+ fprintf(stderr, "%s -includep2p (Set kDNSServiceFlagsIncludeP2P flag)\n", arg0);
+ fprintf(stderr, "%s -includeAWDL (Set kDNSServiceFlagsIncludeAWDL flag)\n", arg0);
+ fprintf(stderr, "%s -intermediates (Set kDNSServiceFlagsReturnIntermediates flag)\n", arg0);
+ fprintf(stderr, "%s -ku (Set kDNSServiceFlagsKnownUnique flag)\n", arg0);
+ fprintf(stderr, "%s -lo (Run dns-sd cmd using local only interface)\n", arg0);
+ fprintf(stderr, "%s -p2p (Use kDNSServiceInterfaceIndexP2P)\n", arg0);
+ fprintf(stderr, "%s -tc (Set kDNSServiceFlagsBackgroundTrafficClass flag)\n", arg0);
+ fprintf(stderr, "%s -test (Run basic API input range tests)\n", arg0);
+ fprintf(stderr, "%s -t1 (Set kDNSServiceFlagsThresholdOne flag)\n", arg0);
+ fprintf(stderr, "%s -tFinder (Set kDNSServiceFlagsThresholdFinder flag)\n", arg0);
+ fprintf(stderr, "%s -timeout (Set kDNSServiceFlagsTimeout flag)\n", arg0);
+ fprintf(stderr, "%s -unicastResponse (Set kDNSServiceFlagsUnicastResponse flag)\n", arg0);
+ fprintf(stderr, "%s -autoTrigger (Set kDNSServiceFlagsAutoTrigger flag)\n", arg0);
+ fprintf(stderr, "%s -enableDNSSEC (Enable DNSSEC validation for the '-Q' query)\n", arg0);
}
}
@@ -896,15 +914,29 @@ static void DNSSD_API reg_reply(DNSServiceRef sdref, const DNSServiceFlags flags
if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
}
+static int snprintf_safe(char *str, size_t size, const char *format, ...)
+{
+ int length = 0;
+ va_list ptr;
+ va_start(ptr, format);
+ int result = vsnprintf(str, size, format, ptr);
+ va_end(ptr);
+ if (result > 0 && size > 0)
+ {
+ length = MIN((size_t)result, size-1);
+ }
+ return length;
+}
+
// Output the wire-format domainname pointed to by rd
static int snprintd(char *p, int max, const unsigned char **rd)
{
const char *const buf = p;
const char *const end = p + max;
- while (**rd)
- {
- p += snprintf(p, end-p, "%.*s.", **rd, *rd+1);
- *rd += 1 + **rd;
+ while (**rd)
+ {
+ p += snprintf_safe(p, end-p, "%.*s.", **rd, *rd+1);
+ *rd += 1 + **rd;
}
*rd += 1; // Advance over the final zero byte
return(p-buf);
@@ -920,18 +952,18 @@ static void ParseDNSSECRecords(uint16_t rrtype, char *rdb, size_t rdb_size, unsi
unsigned char *ptr;
int i;
rdataDS *rrds = (rdataDS *)rd;
- p += snprintf(p, rdb + rdb_size - p, "%d %d %d ",
+ p += snprintf_safe(p, rdb + rdb_size - p, "%d %d %d ",
rrds->alg, swap16(rrds->keyTag), rrds->digestType);
ptr = (unsigned char *)(rd + DS_FIXED_SIZE);
for (i = 0; i < (rdlen - DS_FIXED_SIZE); i++)
- p += snprintf(p, rdb + rdb_size - p, "%x", ptr[i]);
- break;
- }
-
+ p += snprintf_safe(p, rdb + rdb_size - p, "%x", ptr[i]);
+ break;
+ }
+
case kDNSServiceType_DNSKEY:
{
rdataDNSKey *rrkey = (rdataDNSKey *)rd;
- p += snprintf(p, rdb + rdb_size - p, "%d %d %d %u ", swap16(rrkey->flags), rrkey->proto,
+ p += snprintf_safe(p, rdb + rdb_size - p, "%d %d %d %u ", swap16(rrkey->flags), rrkey->proto,
rrkey->alg, (unsigned int)keytag((unsigned char *)rrkey, rdlen));
base64Encode(p, rdb + rdb_size - p, (unsigned char *)(rd + DNSKEY_FIXED_SIZE), rdlen - DNSKEY_FIXED_SIZE);
break;
@@ -979,7 +1011,7 @@ static void ParseDNSSECRecords(uint16_t rrtype, char *rdb, size_t rdb_size, unsi
for (i = 0; i < wlen * 8; i++)
{
if (bmap[i>>3] & (128 >> (i&7)))
- p += snprintf(p, rdb + rdb_size - p, " %s ", DNSTypeName(type + i));
+ p += snprintf_safe(p, rdb + rdb_size - p, " %s ", DNSTypeName(type + i));
}
bmap += wlen;
bitmaplen -= wlen;
@@ -1003,8 +1035,8 @@ static void ParseDNSSECRecords(uint16_t rrtype, char *rdb, size_t rdb_size, unsi
inceptClock = (unsigned long)swap32(rrsig->sigInceptTime);
FormatTime(inceptClock, inceptTimeBuf, sizeof(inceptTimeBuf));
-
- p += snprintf(p, rdb + rdb_size - p, " %-7s %d %d %d %s %s %7d ",
+
+ p += snprintf_safe(p, rdb + rdb_size - p, " %-7s %d %d %d %s %s %7d ",
DNSTypeName(swap16(rrsig->typeCovered)), rrsig->alg, rrsig->labels, swap32(rrsig->origTTL),
expTimeBuf, inceptTimeBuf, swap16(rrsig->keyTag));
@@ -1035,8 +1067,14 @@ static void DNSSD_API qr_reply(DNSServiceRef sdref, const DNSServiceFlags flags,
int unknowntype = 0;
char dnssec_status[15] = "Unknown";
char rr_type[RR_TYPE_SIZE];
- char rr_class[3];
+ char rr_class[6];
DNSServiceFlags check_flags = flags;//local flags for dnssec status checking
+ int8_t enable_dnssec = ((check_flags & kDNSServiceFlagsEnableDNSSEC) != 0);
+ static int8_t enabled_dnssec_before = -1;
+
+ if (enabled_dnssec_before == -1) {
+ enabled_dnssec_before = enable_dnssec;
+ }
(void)sdref; // Unused
(void)ifIndex; // Unused
@@ -1046,10 +1084,7 @@ static void DNSSD_API qr_reply(DNSServiceRef sdref, const DNSServiceFlags flags,
if (num_printed++ == 0)
{
- if (operation == 'D')
- printf("Timestamp A/R if %-30s%-6s%-7s%-18s Rdata\n", "Name", "Type", "Class", "DNSSECStatus");
- else
- printf("Timestamp A/R Flags if %-30s%-6s%-7s Rdata\n", "Name", "Type", "Class");
+ printf("Timestamp A/R Flags if %-30s%-6s%-7s%s Rdata\n", "Name", "Type", "Class", enable_dnssec ? " DNSSECResult " : "");
}
printtimestamp();
@@ -1066,75 +1101,69 @@ static void DNSSD_API qr_reply(DNSServiceRef sdref, const DNSServiceFlags flags,
if (!errorCode) //to avoid printing garbage in rdata
{
- if (!(check_flags & (kDNSServiceFlagsValidate | kDNSServiceFlagsValidateOptional)))
+ switch (rrtype)
{
- switch (rrtype)
- {
- case kDNSServiceType_A:
- snprintf(rdb, sizeof(rdb), "%d.%d.%d.%d", rd[0], rd[1], rd[2], rd[3]);
- break;
-
- case kDNSServiceType_NS:
- case kDNSServiceType_CNAME:
- case kDNSServiceType_PTR:
- case kDNSServiceType_DNAME:
- snprintd(p, sizeof(rdb), &rd);
- break;
-
- case kDNSServiceType_SOA:
- p += snprintd(p, rdb + sizeof(rdb) - p, &rd); // mname
- p += snprintf(p, rdb + sizeof(rdb) - p, " ");
- p += snprintd(p, rdb + sizeof(rdb) - p, &rd); // rname
- snprintf(p, rdb + sizeof(rdb) - p, " Ser %d Ref %d Ret %d Exp %d Min %d",
- ntohl(((uint32_t*)rd)[0]), ntohl(((uint32_t*)rd)[1]), ntohl(((uint32_t*)rd)[2]), ntohl(((uint32_t*)rd)[3]), ntohl(((uint32_t*)rd)[4]));
- break;
-
- case kDNSServiceType_AAAA:
- snprintf(rdb, sizeof(rdb), "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X",
- rd[0x0], rd[0x1], rd[0x2], rd[0x3], rd[0x4], rd[0x5], rd[0x6], rd[0x7],
- rd[0x8], rd[0x9], rd[0xA], rd[0xB], rd[0xC], rd[0xD], rd[0xE], rd[0xF]);
- break;
-
- case kDNSServiceType_SRV:
- p += snprintf(p, rdb + sizeof(rdb) - p, "%d %d %d ", // priority, weight, port
- ntohs(*(unsigned short*)rd), ntohs(*(unsigned short*)(rd+2)), ntohs(*(unsigned short*)(rd+4)));
- rd += 6;
- snprintd(p, rdb + sizeof(rdb) - p, &rd); // target host
- break;
-
- case kDNSServiceType_DS:
- case kDNSServiceType_DNSKEY:
- case kDNSServiceType_NSEC:
- case kDNSServiceType_RRSIG:
- ParseDNSSECRecords(rrtype, rdb, sizeof(rdb), rd, rdlen);
- break;
-
- default:
- snprintf(rdb, sizeof(rdb), "%d bytes%s", rdlen, rdlen ? ":" : "");
- unknowntype = 1;
- break;
- }
- }
- else
- {
- strncpy(rdb, "----", sizeof(rdb));
- //Clear all o/p bits, and then check for dnssec status
- check_flags &= ~kDNSServiceOutputFlags;
- if (check_flags & kDNSServiceFlagsSecure)
- strncpy(dnssec_status, "Secure", sizeof(dnssec_status));
- else if (check_flags & kDNSServiceFlagsInsecure)
- strncpy(dnssec_status, "Insecure", sizeof(dnssec_status));
- else if (check_flags & kDNSServiceFlagsIndeterminate)
- strncpy(dnssec_status, "Indeterminate", sizeof(dnssec_status));
- else if (check_flags & kDNSServiceFlagsBogus)
- strncpy(dnssec_status, "Bogus", sizeof(dnssec_status));
+ case kDNSServiceType_A:
+ snprintf_safe(rdb, sizeof(rdb), "%d.%d.%d.%d", rd[0], rd[1], rd[2], rd[3]);
+ break;
+
+ case kDNSServiceType_NS:
+ case kDNSServiceType_CNAME:
+ case kDNSServiceType_PTR:
+ case kDNSServiceType_DNAME:
+ snprintd(p, sizeof(rdb), &rd);
+ break;
+
+ case kDNSServiceType_SOA:
+ p += snprintd(p, rdb + sizeof(rdb) - p, &rd); // mname
+ p += snprintf_safe(p, rdb + sizeof(rdb) - p, " ");
+ p += snprintd(p, rdb + sizeof(rdb) - p, &rd); // rname
+ snprintf(p, rdb + sizeof(rdb) - p, " Ser %d Ref %d Ret %d Exp %d Min %d",
+ ntohl(((uint32_t*)rd)[0]), ntohl(((uint32_t*)rd)[1]), ntohl(((uint32_t*)rd)[2]), ntohl(((uint32_t*)rd)[3]), ntohl(((uint32_t*)rd)[4]));
+ break;
+
+ case kDNSServiceType_AAAA:
+ snprintf(rdb, sizeof(rdb), "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X",
+ rd[0x0], rd[0x1], rd[0x2], rd[0x3], rd[0x4], rd[0x5], rd[0x6], rd[0x7],
+ rd[0x8], rd[0x9], rd[0xA], rd[0xB], rd[0xC], rd[0xD], rd[0xE], rd[0xF]);
+ break;
+
+ case kDNSServiceType_SRV:
+ p += snprintf_safe(p, rdb + sizeof(rdb) - p, "%d %d %d ", // priority, weight, port
+ ntohs(*(unsigned short*)rd), ntohs(*(unsigned short*)(rd+2)), ntohs(*(unsigned short*)(rd+4)));
+ rd += 6;
+ snprintd(p, rdb + sizeof(rdb) - p, &rd); // target host
+ break;
+
+ case kDNSServiceType_DS:
+ case kDNSServiceType_DNSKEY:
+ case kDNSServiceType_NSEC:
+ case kDNSServiceType_RRSIG:
+ ParseDNSSECRecords(rrtype, rdb, sizeof(rdb), rd, rdlen);
+ break;
+
+ default:
+ snprintf(rdb, sizeof(rdb), "%d bytes%s", rdlen, rdlen ? ":" : "");
+ unknowntype = 1;
+ break;
}
}
- if (operation == 'D')
- printf("%s%3d %-30s%-6s%-7s%-18s %s", op, ifIndex, fullname, rr_type, rr_class, dnssec_status, rdb);
+ if (check_flags & kDNSServiceFlagsSecure)
+ strncpy(dnssec_status, "Secure ", sizeof(dnssec_status));
+ else if (check_flags & kDNSServiceFlagsInsecure)
+ strncpy(dnssec_status, "Insecure ", sizeof(dnssec_status));
+ else if (check_flags & kDNSServiceFlagsIndeterminate)
+ strncpy(dnssec_status, "Indeterminate ", sizeof(dnssec_status));
+ else if (check_flags & kDNSServiceFlagsBogus)
+ strncpy(dnssec_status, "Bogus ", sizeof(dnssec_status));
else
- printf("%s%9X%3d %-30s%-7s%-6s %s", op, flags, ifIndex, fullname, rr_type, rr_class, rdb);
+ strncpy(dnssec_status, " ", sizeof(dnssec_status));
+
+ printf("%s%9X%3d %-30s%-7s%-6s %s%s",
+ op, flags, ifIndex, fullname, rr_type, rr_class, enabled_dnssec_before ? dnssec_status : "", rdb);
+
+
if (unknowntype)
{
while (rd < end)
@@ -1144,6 +1173,8 @@ static void DNSSD_API qr_reply(DNSServiceRef sdref, const DNSServiceFlags flags,
{
if (errorCode == kDNSServiceErr_NoSuchRecord)
printf(" No Such Record");
+ else if (errorCode == kDNSServiceErr_NoAuth)
+ printf(" No Authorization");
else if (errorCode == kDNSServiceErr_Timeout)
{
printf(" No Such Record\n");
@@ -1191,15 +1222,13 @@ static void DNSSD_API addrinfo_reply(DNSServiceRef sdref, const DNSServiceFlags
DNSServiceFlags check_flags = flags;
(void) sdref;
(void) context;
+ unsigned char enable_dnssec = ((check_flags & kDNSServiceFlagsEnableDNSSEC) != 0);
EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
if (num_printed++ == 0)
{
- if (operation == 'g')
- printf("Timestamp A/R if %-25s %-44s %-18s\n", "Hostname", "Address", "DNSSECStatus");
- else
- printf("Timestamp A/R Flags if %-38s %-44s %s\n", "Hostname", "Address", "TTL");
+ printf("Timestamp A/R Flags if %-38s %-44s %s%s\n", "Hostname", "Address", "TTL", enable_dnssec ? "DNSSECResult" : "");
}
printtimestamp();
@@ -1220,26 +1249,20 @@ static void DNSSD_API addrinfo_reply(DNSServiceRef sdref, const DNSServiceFlags
b[0x8], b[0x9], b[0xA], b[0xB], b[0xC], b[0xD], b[0xE], b[0xF], if_name);
}
- //go through this only if you have a dnssec validation status
- if (!errorCode && (check_flags & (kDNSServiceFlagsValidate | kDNSServiceFlagsValidateOptional)))
+ if (enable_dnssec)
{
- strncpy(addr, "----", sizeof(addr));
- //Clear all o/p bits, and then check for dnssec status
- check_flags &= ~kDNSServiceOutputFlags;
if (check_flags & kDNSServiceFlagsSecure)
- strncpy(dnssec_status, "Secure", sizeof(dnssec_status));
+ strncpy(dnssec_status, " Secure", sizeof(dnssec_status));
else if (check_flags & kDNSServiceFlagsInsecure)
- strncpy(dnssec_status, "Insecure", sizeof(dnssec_status));
+ strncpy(dnssec_status, " Insecure", sizeof(dnssec_status));
else if (check_flags & kDNSServiceFlagsIndeterminate)
- strncpy(dnssec_status, "Indeterminate", sizeof(dnssec_status));
+ strncpy(dnssec_status, " Indeterminate", sizeof(dnssec_status));
else if (check_flags & kDNSServiceFlagsBogus)
- strncpy(dnssec_status, "Bogus", sizeof(dnssec_status));
+ strncpy(dnssec_status, " Bogus", sizeof(dnssec_status));
}
- if (operation == 'g')
- printf("%s%3d %-25s %-44s %-18s", op, interfaceIndex, hostname, addr, dnssec_status);
- else
- printf("%s%9X%3d %-38s %-44s %d", op, flags, interfaceIndex, hostname, addr, ttl);
+ printf("%s%9X%3d %-38s %-44s %d%s", op, flags, interfaceIndex, hostname, addr, ttl, enable_dnssec ? dnssec_status : "");
+
if (errorCode)
{
if (errorCode == kDNSServiceErr_NoSuchRecord)
@@ -1401,12 +1424,14 @@ static DNSServiceErrorType RegisterProxyAddressRecord(DNSServiceRef sdref, const
#define HexPair(P) ((HexVal((P)[0]) << 4) | HexVal((P)[1]))
+#define MAXTXTRecordSize 8900
static DNSServiceErrorType RegisterService(DNSServiceRef *sdref,
const char *nam, const char *typ, const char *dom, const char *host, const char *port, int argc, char **argv, DNSServiceFlags flags)
{
uint16_t PortAsNumber = atoi(port);
Opaque16 registerPort = { { PortAsNumber >> 8, PortAsNumber & 0xFF } };
- unsigned char txt[2048] = "";
+ unsigned char txt[MAXTXTRecordSize];
+ txt[0] = '\0';
unsigned char *ptr = txt;
int i;
@@ -1422,9 +1447,13 @@ static DNSServiceErrorType RegisterService(DNSServiceRef *sdref,
for (i = 0; i < argc; i++)
{
const char *p = argv[i];
+ if (ptr >= txt + sizeof(txt))
+ return kDNSServiceErr_BadParam;
*ptr = 0;
- while (*p && *ptr < 255 && ptr + 1 + *ptr < txt+sizeof(txt))
+ while (*p && *ptr < 255)
{
+ if (ptr + 1 + *ptr >= txt + sizeof(txt))
+ return kDNSServiceErr_BadParam;
if (p[0] != '\\' || p[1] == 0) { ptr[++*ptr] = *p; p+=1; }
else if (p[1] == 'x' && isxdigit(p[2]) && isxdigit(p[3])) { ptr[++*ptr] = HexPair(p+2); p+=4; }
else { ptr[++*ptr] = p[1]; p+=2; }
@@ -1836,13 +1865,16 @@ static int API_input_range_test()
return 0;
}
+#ifdef APPLE_OSX_mDNSResponder
+static void handle_state_dump_request(uint8_t if_compress_state_dump, uint8_t if_dump_to_stdout);
+#endif // APPLE_OSX_mDNSResponder
int main(int argc, char **argv)
{
DNSServiceErrorType err;
char buffer[TypeBufferSize], *typ, *dom;
int opi;
DNSServiceFlags flags = 0;
- int optional = 0;
+ unsigned char enable_dnssec = 0;
// Extract the program name from argv[0], which by convention contains the path to this executable.
// Note that this is just a voluntary convention, not enforced by the kernel --
@@ -2005,12 +2037,12 @@ int main(int argc, char **argv)
printf("Setting kDNSServiceFlagsAutoTrigger\n");
}
- if (argc > 1 && !strcasecmp(argv[1], "-optional"))
+ if (argc > 1 && !strcasecmp(argv[1], "-enableDNSSEC"))
{
argc--;
argv++;
- optional = 1;
- printf("Setting DNSSEC optional flag\n");
+ enable_dnssec = 1;
+ printf("Enable DNSSEC validation for the '-Q' query\n");
}
if (argc > 2 && !strcmp(argv[1], "-i"))
@@ -2099,7 +2131,6 @@ int main(int argc, char **argv)
err = RegisterService(&client, argv[opi+0], gettype(buffer, argv[opi+1]), argv[opi+2], argv[opi+4], argv[opi+3], argc-(opi+6), argv+(opi+6), flags);
break;
- case 'D':
case 'q':
case 'Q':
case 'C': {
@@ -2107,20 +2138,14 @@ int main(int argc, char **argv)
flags |= kDNSServiceFlagsReturnIntermediates;
if (operation == 'q')
flags |= kDNSServiceFlagsSuppressUnusable;
+ if (enable_dnssec)
+ flags |= kDNSServiceFlagsEnableDNSSEC;
if (argc < opi+1)
goto Fail;
rrtype = (argc <= opi+1) ? kDNSServiceType_A : GetRRType(argv[opi+1]);
rrclass = (argc <= opi+2) ? kDNSServiceClass_IN : GetRRClass(argv[opi+2]);
if (rrtype == kDNSServiceType_TXT || rrtype == kDNSServiceType_PTR)
flags |= kDNSServiceFlagsLongLivedQuery;
- if (operation == 'D')
- {
- flags |= kDNSServiceFlagsSuppressUnusable;
- if (optional)
- flags |= kDNSServiceFlagsValidateOptional;
- else
- flags |= kDNSServiceFlagsValidate;
- }
err = DNSServiceQueryRecord(&client, flags, opinterface, argv[opi+0], rrtype, rrclass, qr_reply, NULL);
break;
}
@@ -2184,19 +2209,10 @@ int main(int argc, char **argv)
break;
}
- case 'g':
case 'G': {
flags |= kDNSServiceFlagsReturnIntermediates;
- if (operation == 'g')
- {
- flags |= kDNSServiceFlagsSuppressUnusable;
- if (optional)
- flags |= kDNSServiceFlagsValidateOptional;
- else
- flags |= kDNSServiceFlagsValidate;
- }
- if (argc != opi+2)
+ if (argc != opi+2)
goto Fail;
else
err = DNSServiceGetAddrInfo(&client, flags, opinterface, GetProtocol(argv[opi+0]), argv[opi+1], addrinfo_reply, NULL);
@@ -2245,11 +2261,43 @@ int main(int argc, char **argv)
else printf("Currently running daemon (system service) is version %d.%d.%d\n", v / 10000, v / 100 % 100, v % 100);
exit(0);
}
+#ifdef APPLE_OSX_mDNSResponder
+ case 'O': {
+ // check if the user specifies the flag "-compress"
+ uint8_t if_compress_state_dump = 0;
+ uint8_t if_dump_to_stdout = 0;
+
+ if (argc > opi+1) {
+ printf("dns-sd: illegal option count\n");
+ goto Fail;
+ }
+
+ if (argc == opi+1) {
+ const char *param = argv[opi];
+ if (strcasecmp("-compress", param) == 0) {
+ if_compress_state_dump = 1;
+ } else if (strcasecmp("-stdout", param) == 0) {
+ if_dump_to_stdout = 1;
+ } else {
+ printf("dns-sd: illegal option %s \n", param);
+ goto Fail;
+ }
+ }
+ handle_state_dump_request(if_compress_state_dump, if_dump_to_stdout);
+ err = kDNSServiceErr_NoError;
+ break;
+ }
+#endif // APPLE_OSX_mDNSResponder
case 'H': goto Fail;
default: goto Fail;
}
+#ifdef APPLE_OSX_mDNSResponder
+ // state dump does not need to create DNSServiceRef, so we can return directly here without cleaning up.
+ if (operation == 'O')
+ return 0;
+#endif // APPLE_OSX_mDNSResponder
if (!client || err != kDNSServiceErr_NoError)
{
@@ -2270,8 +2318,72 @@ Fail:
if (operation == 'H') print_usage(a0,1);
else print_usage(a0,0);
return 0;
+}
+
+#ifdef APPLE_OSX_mDNSResponder
+/*
+ * if_compress_state_dump and if_dump_to_stdout cannot be set at the same time.
+ */
+static void handle_state_dump_request(uint8_t if_compress_state_dump, uint8_t if_dump_to_stdout)
+{
+ // create xpc connection to the xpc server for log utility
+ xpc_connection_t log_utility_connection = xpc_connection_create_mach_service(kDNSLogUtilityService, dispatch_get_main_queue(), XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
+ xpc_connection_set_event_handler(log_utility_connection, ^(xpc_object_t event){
+ printf("Connecting to %s, status: %s\n", kDNSLogUtilityService, xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION));
+ });
+ xpc_connection_resume(log_utility_connection);
+
+ // set option for the state dump
+ xpc_object_t xpc_dict = xpc_dictionary_create(NULL, NULL, 0);
+ uint64_t dump_option;
+ if (if_compress_state_dump) {
+ dump_option = full_state_with_compression;
+ }
+ else if (if_dump_to_stdout) {
+ // we pass the stdout directly to xpc server
+ dump_option = full_state_to_stdout;
+ xpc_dictionary_set_fd(xpc_dict, kDNSStateDumpFD, STDOUT_FILENO);
+ }
+ else {
+ dump_option = full_state;
+ }
+
+ xpc_dictionary_set_uint64(xpc_dict, kDNSStateDump, dump_option);
+
+ // send the request and handle the response from xpc server
+ xpc_connection_send_message_with_reply(log_utility_connection, xpc_dict, dispatch_get_main_queue(), ^(xpc_object_t recv_msg){
+ xpc_type_t msg_type = xpc_get_type(recv_msg);
+
+ if (msg_type != XPC_TYPE_DICTIONARY) {
+ printf("Received unexpected reply from daemon, error: \"%s\"\nUnexpected reply Contents:\n%s\n",
+ xpc_dictionary_get_string(recv_msg, XPC_ERROR_KEY_DESCRIPTION), xpc_copy_description(recv_msg));
+ exit(1);
+ }
+
+ // get the response dictionary
+ uint32_t return_code = (uint32_t)xpc_dictionary_get_uint64(recv_msg, kDNSDaemonReply);
+ if (return_code != kDNSMsg_NoError) {
+ const char *error_description = xpc_dictionary_get_string(recv_msg, kDNSErrorDescription);
+ printf("XPC service returns error, description: %s\n", error_description);
+ exit(1);
+ }
+
+ // print the state information returned from the XPC server
+ if (dump_option != full_state_to_stdout) {
+ const char *path = xpc_dictionary_get_string(recv_msg, kDNSDumpFilePath);
+ printf("State Dump Is Saved to: %s\n", path);
+ }
+
+ int64_t time_used = xpc_dictionary_get_int64(recv_msg, kDNSStateDumpTimeUsed);
+ printf(" Time Used: %" PRId64 " ms\n", time_used);
+ xpc_release(xpc_dict);
+ exit(0);
+ });
+
+ dispatch_main();
}
+#endif // APPLE_OSX_mDNSResponder
// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
diff --git a/usr/src/contrib/mDNSResponder/README b/usr/src/contrib/mDNSResponder/README
index 73c8188fba..33d3d0b263 100644
--- a/usr/src/contrib/mDNSResponder/README
+++ b/usr/src/contrib/mDNSResponder/README
@@ -24,23 +24,24 @@
The mdns vendor source repository is at https://github.com/illumos/mdns/.
+Updated from upstream version mDNSResponder-1310.80.1
Updated from upstream version mDNSResponder-878.260.1
Updated from upstream version mDNSResponder-878.1.1
Updated from upstream version mDNSResponder-625.41.2
Updated from upstream version mDNSResponder-576.30.4
-Multicast DNS and Service Discovery support in Solaris using the
+Multicast DNS and Service Discovery support in illumos using the
Apple Bonjour source code (v107.6). Apple Bonjour source can be
downloaded from:
- http://developer.apple.com/networking/bonjour/download/
+ https://opensource.apple.com/tarballs/mDNSResponder/
The following components are integrated from the Apple Bonjour
-source in Solaris:
+source in illumos:
libdns_sd: usr/src/lib/libdns_sd <dns_sd.h>
mdnsd: usr/src/cmd/cmd-inet/usr.lib/mdnsd
dns-sd: usr/src/cmd/cmd-inet/usr.bin/dns-sd
Following fixes have been made to the Apple Bonjour source
-integrated in Solaris:
+integrated in illumos:
* 64-bit support by adding pad bytes in ipc_msg_hdr_struct
* 64-bit support in libjdns_sd, dnssd.jar (JNISupport.c, DNSSD.java)
* mdnsd switches to user 'noaccess' and not 'nobody' after init
diff --git a/usr/src/contrib/mDNSResponder/mDNSCore/CryptoAlg.c b/usr/src/contrib/mDNSResponder/mDNSCore/CryptoAlg.c
deleted file mode 100644
index 0008405ddd..0000000000
--- a/usr/src/contrib/mDNSResponder/mDNSCore/CryptoAlg.c
+++ /dev/null
@@ -1,280 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2011-2012 Apple Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// ***************************************************************************
-// CryptoAlg.c:
-// Interface to DNSSEC cryptographic algorithms. The crypto support itself is
-// provided by the platform and the functions in this file just provide an
-// interface to access them in a more generic way.
-// ***************************************************************************
-
-#include "mDNSEmbeddedAPI.h"
-#include "CryptoAlg.h"
-
-AlgFuncs *DigestAlgFuncs[DIGEST_TYPE_MAX];
-AlgFuncs *CryptoAlgFuncs[CRYPTO_ALG_MAX];
-AlgFuncs *EncAlgFuncs[ENC_ALG_MAX];
-
-mDNSexport mStatus DigestAlgInit(mDNSu8 digestType, AlgFuncs *func)
-{
- if (digestType >= DIGEST_TYPE_MAX)
- {
- LogMsg("DigestAlgInit: digestType %d exceeds bounds", digestType);
- return mStatus_BadParamErr;
- }
- // As digestTypes may not be consecutive, check for specific digest types
- // that we support
- if (digestType != SHA1_DIGEST_TYPE &&
- digestType != SHA256_DIGEST_TYPE)
- {
- LogMsg("DigestAlgInit: digestType %d not supported", digestType);
- return mStatus_BadParamErr;
- }
- DigestAlgFuncs[digestType] = func;
- return mStatus_NoError;
-}
-
-mDNSexport mStatus CryptoAlgInit(mDNSu8 alg, AlgFuncs *func)
-{
- if (alg >= CRYPTO_ALG_MAX)
- {
- LogMsg("CryptoAlgInit: alg %d exceeds bounds", alg);
- return mStatus_BadParamErr;
- }
- // As algs may not be consecutive, check for specific algorithms
- // that we support
- if (alg != CRYPTO_RSA_SHA1 && alg != CRYPTO_RSA_SHA256 && alg != CRYPTO_RSA_SHA512 &&
- alg != CRYPTO_DSA_NSEC3_SHA1 && alg != CRYPTO_RSA_NSEC3_SHA1)
- {
- LogMsg("CryptoAlgInit: alg %d not supported", alg);
- return mStatus_BadParamErr;
- }
-
- CryptoAlgFuncs[alg] = func;
- return mStatus_NoError;
-}
-
-mDNSexport mStatus EncAlgInit(mDNSu8 alg, AlgFuncs *func)
-{
- if (alg >= ENC_ALG_MAX)
- {
- LogMsg("EncAlgInit: alg %d exceeds bounds", alg);
- return mStatus_BadParamErr;
- }
-
- // As algs may not be consecutive, check for specific algorithms
- // that we support
- if (alg != ENC_BASE32 && alg != ENC_BASE64)
- {
- LogMsg("EncAlgInit: alg %d not supported", alg);
- return mStatus_BadParamErr;
- }
-
- EncAlgFuncs[alg] = func;
- return mStatus_NoError;
-}
-
-mDNSexport AlgContext *AlgCreate(AlgType type, mDNSu8 alg)
-{
- AlgFuncs *func = mDNSNULL;
- AlgContext *ctx;
-
- if (type == CRYPTO_ALG)
- {
- if (alg >= CRYPTO_ALG_MAX) return mDNSNULL;
- func = CryptoAlgFuncs[alg];
- }
- else if (type == DIGEST_ALG)
- {
- if (alg >= DIGEST_TYPE_MAX) return mDNSNULL;
- func = DigestAlgFuncs[alg];
- }
- else if (type == ENC_ALG)
- {
- if (alg >= ENC_ALG_MAX) return mDNSNULL;
- func = EncAlgFuncs[alg];
- }
-
- if (!func)
- {
- // If there is no support from the platform, this case can happen.
- LogInfo("AlgCreate: func is NULL");
- return mDNSNULL;
- }
-
- if (func->Create)
- {
- mStatus err;
- ctx = mDNSPlatformMemAllocate(sizeof(AlgContext));
- if (!ctx) return mDNSNULL;
- // Create expects ctx->alg to be initialized
- ctx->alg = alg;
- err = func->Create(ctx);
- if (err == mStatus_NoError)
- {
- ctx->type = type;
- return ctx;
- }
- mDNSPlatformMemFree(ctx);
- }
- return mDNSNULL;
-}
-
-mDNSexport mStatus AlgDestroy(AlgContext *ctx)
-{
- AlgFuncs *func = mDNSNULL;
-
- if (ctx->type == CRYPTO_ALG)
- func = CryptoAlgFuncs[ctx->alg];
- else if (ctx->type == DIGEST_ALG)
- func = DigestAlgFuncs[ctx->alg];
- else if (ctx->type == ENC_ALG)
- func = EncAlgFuncs[ctx->alg];
-
- if (!func)
- {
- LogMsg("AlgDestroy: ERROR!! func is NULL");
- mDNSPlatformMemFree(ctx);
- return mStatus_BadParamErr;
- }
-
- if (func->Destroy)
- func->Destroy(ctx);
-
- mDNSPlatformMemFree(ctx);
- return mStatus_NoError;
-}
-
-mDNSexport mDNSu32 AlgLength(AlgContext *ctx)
-{
- AlgFuncs *func = mDNSNULL;
-
- if (ctx->type == CRYPTO_ALG)
- func = CryptoAlgFuncs[ctx->alg];
- else if (ctx->type == DIGEST_ALG)
- func = DigestAlgFuncs[ctx->alg];
- else if (ctx->type == ENC_ALG)
- func = EncAlgFuncs[ctx->alg];
-
- // This should never happen as AlgCreate would have failed
- if (!func)
- {
- LogMsg("AlgLength: ERROR!! func is NULL");
- return 0;
- }
-
- if (func->Length)
- return (func->Length(ctx));
- else
- return 0;
-}
-
-mDNSexport mStatus AlgAdd(AlgContext *ctx, const void *data, mDNSu32 len)
-{
- AlgFuncs *func = mDNSNULL;
-
- if (ctx->type == CRYPTO_ALG)
- func = CryptoAlgFuncs[ctx->alg];
- else if (ctx->type == DIGEST_ALG)
- func = DigestAlgFuncs[ctx->alg];
- else if (ctx->type == ENC_ALG)
- func = EncAlgFuncs[ctx->alg];
-
- // This should never happen as AlgCreate would have failed
- if (!func)
- {
- LogMsg("AlgAdd: ERROR!! func is NULL");
- return mStatus_BadParamErr;
- }
-
- if (func->Add)
- return (func->Add(ctx, data, len));
- else
- return mStatus_BadParamErr;
-}
-
-mDNSexport mStatus AlgVerify(AlgContext *ctx, mDNSu8 *key, mDNSu32 keylen, mDNSu8 *signature, mDNSu32 siglen)
-{
- AlgFuncs *func = mDNSNULL;
-
- if (ctx->type == CRYPTO_ALG)
- func = CryptoAlgFuncs[ctx->alg];
- else if (ctx->type == DIGEST_ALG)
- func = DigestAlgFuncs[ctx->alg];
- else if (ctx->type == ENC_ALG)
- func = EncAlgFuncs[ctx->alg];
-
- // This should never happen as AlgCreate would have failed
- if (!func)
- {
- LogMsg("AlgVerify: ERROR!! func is NULL");
- return mStatus_BadParamErr;
- }
-
- if (func->Verify)
- return (func->Verify(ctx, key, keylen, signature, siglen));
- else
- return mStatus_BadParamErr;
-}
-
-mDNSexport mDNSu8* AlgEncode(AlgContext *ctx)
-{
- AlgFuncs *func = mDNSNULL;
-
- if (ctx->type == CRYPTO_ALG)
- func = CryptoAlgFuncs[ctx->alg];
- else if (ctx->type == DIGEST_ALG)
- func = DigestAlgFuncs[ctx->alg];
- else if (ctx->type == ENC_ALG)
- func = EncAlgFuncs[ctx->alg];
-
- // This should never happen as AlgCreate would have failed
- if (!func)
- {
- LogMsg("AlgEncode: ERROR!! func is NULL");
- return mDNSNULL;
- }
-
- if (func->Encode)
- return (func->Encode(ctx));
- else
- return mDNSNULL;
-}
-
-mDNSexport mStatus AlgFinal(AlgContext *ctx, void *data, mDNSu32 len)
-{
- AlgFuncs *func = mDNSNULL;
-
- if (ctx->type == CRYPTO_ALG)
- func = CryptoAlgFuncs[ctx->alg];
- else if (ctx->type == DIGEST_ALG)
- func = DigestAlgFuncs[ctx->alg];
- else if (ctx->type == ENC_ALG)
- func = EncAlgFuncs[ctx->alg];
-
- // This should never happen as AlgCreate would have failed
- if (!func)
- {
- LogMsg("AlgEncode: ERROR!! func is NULL");
- return mDNSNULL;
- }
-
- if (func->Final)
- return (func->Final(ctx, data, len));
- else
- return mStatus_BadParamErr;
-}
diff --git a/usr/src/contrib/mDNSResponder/mDNSCore/CryptoAlg.h b/usr/src/contrib/mDNSResponder/mDNSCore/CryptoAlg.h
deleted file mode 100644
index c21507e4b1..0000000000
--- a/usr/src/contrib/mDNSResponder/mDNSCore/CryptoAlg.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2011-2012 Apple Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __CRYPTO_ALG_H
-#define __CRYPTO_ALG_H
-
-typedef enum
-{
- CRYPTO_ALG,
- DIGEST_ALG,
- ENC_ALG,
-} AlgType;
-
-typedef struct
-{
- void *context;
- AlgType type;
- mDNSu8 alg;
-} AlgContext;
-
-typedef struct
-{
- mStatus (*Create)(AlgContext *ctx);
- mStatus (*Destroy)(AlgContext *ctx);
- mDNSu32 (*Length)(AlgContext *ctx);
- mStatus (*Add)(AlgContext *ctx, const void *data, mDNSu32 len);
- // Verify the ctx using the key and compare it against signature/siglen
- mStatus (*Verify)(AlgContext *ctx, mDNSu8 *key, mDNSu32 keylen, mDNSu8 *signature, mDNSu32 siglen);
- // Encode the data and return the encoded data
- mDNSu8* (*Encode)(AlgContext *ctx);
- // Return the finalized data in data whose length is len (used by hash algorithms)
- mStatus (*Final)(AlgContext *ctx, void *data, mDNSu32 len);
-} AlgFuncs;
-
-mDNSexport mStatus DigestAlgInit(mDNSu8 digestType, AlgFuncs *func);
-mDNSexport mStatus CryptoAlgInit(mDNSu8 algType, AlgFuncs *func);
-mDNSexport mStatus EncAlgInit(mDNSu8 algType, AlgFuncs *func);
-
-
-extern AlgContext *AlgCreate(AlgType type, mDNSu8 alg);
-extern mStatus AlgDestroy(AlgContext *ctx);
-extern mDNSu32 AlgLength(AlgContext *ctx);
-extern mStatus AlgAdd(AlgContext *ctx, const void *data, mDNSu32 len);
-extern mStatus AlgVerify(AlgContext *ctx, mDNSu8 *key, mDNSu32 keylen, mDNSu8 *signature, mDNSu32 siglen);
-extern mDNSu8* AlgEncode(AlgContext *ctx);
-extern mStatus AlgFinal(AlgContext *ctx, void *data, mDNSu32 len);
-
-#endif // __CRYPTO_ALG_H
diff --git a/usr/src/contrib/mDNSResponder/mDNSCore/DNSCommon.c b/usr/src/contrib/mDNSResponder/mDNSCore/DNSCommon.c
index 35d4e2649c..057981dcfc 100644
--- a/usr/src/contrib/mDNSResponder/mDNSCore/DNSCommon.c
+++ b/usr/src/contrib/mDNSResponder/mDNSCore/DNSCommon.c
@@ -1,6 +1,6 @@
-/* -*- Mode: C; tab-width: 4 -*-
+/* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*-
*
- * Copyright (c) 2002-2018 Apple Inc. All rights reserved.
+ * Copyright (c) 2002-2020 Apple Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,15 +15,13 @@
* limitations under the License.
*/
+#ifndef STANDALONE
// Set mDNS_InstantiateInlines to tell mDNSEmbeddedAPI.h to instantiate inline functions, if necessary
#define mDNS_InstantiateInlines 1
#include "DNSCommon.h"
-#include "CryptoAlg.h"
-#include "anonymous.h"
-
-#ifdef UNIT_TEST
-#include "unittest.h"
-#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+#include "dnssec_v2.h"
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
// Disable certain benign warnings with Microsoft compilers
#if (defined(_MSC_VER))
@@ -44,10 +42,9 @@
mDNSexport const mDNSInterfaceID mDNSInterface_Any = 0;
mDNSexport const mDNSInterfaceID mDNSInterfaceMark = (mDNSInterfaceID)-1;
mDNSexport const mDNSInterfaceID mDNSInterface_LocalOnly = (mDNSInterfaceID)-2;
-mDNSexport const mDNSInterfaceID mDNSInterface_Unicast = (mDNSInterfaceID)-3;
-mDNSexport const mDNSInterfaceID mDNSInterface_P2P = (mDNSInterfaceID)-4;
-mDNSexport const mDNSInterfaceID uDNSInterfaceMark = (mDNSInterfaceID)-5;
-mDNSexport const mDNSInterfaceID mDNSInterface_BLE = (mDNSInterfaceID)-6;
+mDNSexport const mDNSInterfaceID mDNSInterface_P2P = (mDNSInterfaceID)-3;
+mDNSexport const mDNSInterfaceID uDNSInterfaceMark = (mDNSInterfaceID)-4;
+mDNSexport const mDNSInterfaceID mDNSInterface_BLE = (mDNSInterfaceID)-5;
// Note: Microsoft's proposed "Link Local Multicast Name Resolution Protocol" (LLMNR) is essentially a limited version of
// Multicast DNS, using the same packet formats, naming syntax, and record types as Multicast DNS, but on a different UDP
@@ -108,16 +105,15 @@ mDNSexport const mDNSOpaque16 zeroID = { { 0, 0 } };
mDNSexport const mDNSOpaque16 onesID = { { 255, 255 } };
mDNSexport const mDNSOpaque16 QueryFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery, 0 } };
mDNSexport const mDNSOpaque16 uQueryFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery | kDNSFlag0_RD, 0 } };
-mDNSexport const mDNSOpaque16 DNSSecQFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery | kDNSFlag0_RD, kDNSFlag1_CD } };
mDNSexport const mDNSOpaque16 ResponseFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery | kDNSFlag0_AA, 0 } };
mDNSexport const mDNSOpaque16 UpdateReqFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_Update, 0 } };
mDNSexport const mDNSOpaque16 UpdateRespFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update, 0 } };
-mDNSexport const mDNSOpaque16 SubscribeFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_Subscribe, 0 } };
-mDNSexport const mDNSOpaque16 UnSubscribeFlags= { { kDNSFlag0_QR_Query | kDNSFlag0_OP_UnSubscribe, 0 } };
mDNSexport const mDNSOpaque64 zeroOpaque64 = { { 0 } };
mDNSexport const mDNSOpaque128 zeroOpaque128 = { { 0 } };
+extern mDNS mDNSStorage;
+
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
@@ -132,6 +128,21 @@ mDNSexport mDNSBool mDNSv4AddrIsRFC1918(const mDNSv4Addr * const addr)
(addr->b[0] == 192 && addr->b[1] == 168)); // 192.168/16
}
+mDNSexport const char *DNSScopeToString(mDNSu32 scope)
+{
+ switch (scope)
+ {
+ case kScopeNone:
+ return "Unscoped";
+ case kScopeInterfaceID:
+ return "InterfaceScoped";
+ case kScopeServiceID:
+ return "ServiceScoped";
+ default:
+ return "Unknown";
+ }
+}
+
mDNSexport void mDNSAddrMapIPv4toIPv6(mDNSv4Addr* in, mDNSv6Addr* out)
{
out->l[0] = 0;
@@ -200,6 +211,8 @@ mDNSexport char *DNSTypeName(mDNSu16 rrtype)
case kDNSType_RRSIG: return("RRSIG");
case kDNSType_DNSKEY: return("DNSKEY");
case kDNSType_DS: return("DS");
+ case kDNSType_SVCB: return("SVCB");
+ case kDNSType_HTTPS: return("HTTPS");
case kDNSQType_ANY: return("ANY");
default: {
static char buffer[16];
@@ -209,36 +222,23 @@ mDNSexport char *DNSTypeName(mDNSu16 rrtype)
}
}
-mDNSlocal char *DNSSECAlgName(mDNSu8 alg)
+mDNSexport const char *mStatusDescription(mStatus error)
{
- switch (alg)
- {
- case CRYPTO_RSA_SHA1: return "RSA_SHA1";
- case CRYPTO_DSA_NSEC3_SHA1: return "DSA_NSEC3_SHA1";
- case CRYPTO_RSA_NSEC3_SHA1: return "RSA_NSEC3_SHA1";
- case CRYPTO_RSA_SHA256: return "RSA_SHA256";
- case CRYPTO_RSA_SHA512: return "RSA_SHA512";
- default: {
- static char algbuffer[16];
- mDNS_snprintf(algbuffer, sizeof(algbuffer), "ALG%d", alg);
- return(algbuffer);
- }
- }
-}
+ const char *error_description;
+ switch (error) {
+ case mStatus_NoError:
+ error_description = "mStatus_NoError";
+ break;
+ case mStatus_BadParamErr:
+ error_description = "mStatus_BadParamErr";
+ break;
-mDNSlocal char *DNSSECDigestName(mDNSu8 digest)
-{
- switch (digest)
- {
- case SHA1_DIGEST_TYPE: return "SHA1";
- case SHA256_DIGEST_TYPE: return "SHA256";
- default:
- {
- static char digbuffer[16];
- mDNS_snprintf(digbuffer, sizeof(digbuffer), "DIG%d", digest);
- return(digbuffer);
- }
+ default:
+ error_description = "mStatus_UnknownDescription";
+ break;
}
+
+ return error_description;
}
mDNSexport mDNSu32 swap32(mDNSu32 x)
@@ -253,53 +253,6 @@ mDNSexport mDNSu16 swap16(mDNSu16 x)
return (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
}
-// RFC 4034 Appendix B: Get the keyid of a DNS KEY. It is not transmitted
-// explicitly on the wire.
-//
-// Note: This just helps narrow down the list of keys to look at. It is possible
-// for two DNS keys to have the same ID i.e., key ID is not a unqiue tag. We ignore
-// MD5 keys.
-//
-// 1st argument - the RDATA part of the DNSKEY RR
-// 2nd argument - the RDLENGTH
-//
-mDNSlocal mDNSu32 keytag(mDNSu8 *key, mDNSu32 keysize)
-{
- unsigned long ac;
- unsigned int i;
-
- for (ac = 0, i = 0; i < keysize; ++i)
- ac += (i & 1) ? key[i] : key[i] << 8;
- ac += (ac >> 16) & 0xFFFF;
- return ac & 0xFFFF;
-}
-
-mDNSexport int baseEncode(char *buffer, int blen, const mDNSu8 *data, int len, int encAlg)
-{
- AlgContext *ctx;
- mDNSu8 *outputBuffer;
- int length;
-
- ctx = AlgCreate(ENC_ALG, encAlg);
- if (!ctx)
- {
- LogMsg("baseEncode: AlgCreate failed\n");
- return 0;
- }
- AlgAdd(ctx, data, len);
- outputBuffer = AlgEncode(ctx);
- length = 0;
- if (outputBuffer)
- {
- // Note: don't include any spaces in the format string below. This
- // is also used by NSEC3 code for proving non-existence where it
- // needs the base32 encoding without any spaces etc.
- length = mDNS_snprintf(buffer, blen, "%s", outputBuffer);
- }
- AlgDestroy(ctx);
- return length;
-}
-
mDNSlocal void PrintTypeBitmap(const mDNSu8 *bmap, int bitmaplen, char *const buffer, mDNSu32 length)
{
int win, wlen, type;
@@ -338,36 +291,6 @@ mDNSlocal void PrintTypeBitmap(const mDNSu8 *bmap, int bitmaplen, char *const bu
}
}
-// Parse the fields beyond the base header. NSEC3 should have been validated.
-mDNSexport void NSEC3Parse(const ResourceRecord *const rr, mDNSu8 **salt, int *hashLength, mDNSu8 **nxtName, int *bitmaplen, mDNSu8 **bitmap)
-{
- const RDataBody2 *const rdb = (RDataBody2 *)rr->rdata->u.data;
- rdataNSEC3 *nsec3 = (rdataNSEC3 *)rdb->data;
- mDNSu8 *p = (mDNSu8 *)&nsec3->salt;
- int hlen;
-
- if (salt)
- {
- if (nsec3->saltLength)
- *salt = p;
- else
- *salt = mDNSNULL;
- }
- p += nsec3->saltLength;
- // p is pointing at hashLength
- hlen = (int)*p;
- if (hashLength)
- *hashLength = hlen;
- p++;
- if (nxtName)
- *nxtName = p;
- p += hlen;
- if (bitmaplen)
- *bitmaplen = rr->rdlength - (int)(p - rdb->data);
- if (bitmap)
- *bitmap = p;
-}
-
// Note slight bug: this code uses the rdlength from the ResourceRecord object, to display
// the rdata from the RDataBody object. Sometimes this could be the wrong length -- but as
// long as this routine is only used for debugging messages, it probably isn't a big problem.
@@ -396,12 +319,27 @@ mDNSexport char *GetRRDisplayString_rdb(const ResourceRecord *const rr, const RD
case kDNSType_HINFO: // Display this the same as TXT (show all constituent strings)
case kDNSType_TXT: {
const mDNSu8 *t = rd->txt.c;
- while (t < rd->txt.c + rr->rdlength)
+ const mDNSu8 *const rdLimit = rd->data + rr->rdlength;
+ const char *separator = "";
+
+ while (t < rdLimit)
{
- length += mDNS_snprintf(buffer+length, RemSpc, "%s%#s", t > rd->txt.c ? "¦" : "", t);
- t += 1 + t[0];
+ mDNSu32 characterStrLength = *t;
+ if (characterStrLength + 1 > (mDNSu32)(rdLimit - t)) // Character string goes out of boundary.
+ {
+ const mDNSu8 *const remainderStart = t + 1;
+ const mDNSu32 remainderLength = (mDNSu32)(rdLimit - remainderStart);
+ length += mDNS_snprintf(buffer + length, RemSpc, "%s%.*s<<OUT OF BOUNDARY CHARACTER STRING>>", separator,
+ remainderLength, remainderStart);
+ (void)length; // Acknowledge "dead store" analyzer warning.
+ break;
+ }
+ length += mDNS_snprintf(buffer+length, RemSpc, "%s%.*s", separator, characterStrLength, t + 1);
+ separator = "¦";
+ t += 1 + characterStrLength;
}
- } break;
+ }
+ break;
case kDNSType_AAAA: mDNS_snprintf(buffer+length, RemSpc, "%.16a", &rd->ipv6); break;
case kDNSType_SRV: mDNS_snprintf(buffer+length, RemSpc, "%u %u %u %##s",
@@ -465,95 +403,13 @@ mDNSexport char *GetRRDisplayString_rdb(const ResourceRecord *const rr, const RD
}
break;
- case kDNSType_NSEC3: {
- rdataNSEC3 *nsec3 = (rdataNSEC3 *)rd->data;
- const mDNSu8 *p = (mDNSu8 *)&nsec3->salt;
- int hashLength, bitmaplen, i;
-
- length += mDNS_snprintf(buffer+length, RemSpc, "\t%s %d %d ",
- DNSSECDigestName(nsec3->alg), nsec3->flags, swap16(nsec3->iterations));
-
- if (!nsec3->saltLength)
- {
- length += mDNS_snprintf(buffer+length, RemSpc, "-");
- }
- else
- {
- for (i = 0; i < nsec3->saltLength; i++)
- {
- length += mDNS_snprintf(buffer+length, RemSpc, "%x", p[i]);
- }
- }
-
- // put a space at the end
- length += mDNS_snprintf(buffer+length, RemSpc, " ");
-
- p += nsec3->saltLength;
- // p is pointing at hashLength
- hashLength = (int)*p++;
-
- length += baseEncode(buffer + length, RemSpc, p, hashLength, ENC_BASE32);
-
- // put a space at the end
- length += mDNS_snprintf(buffer+length, RemSpc, " ");
-
- p += hashLength;
- bitmaplen = rr->rdlength - (int)(p - rd->data);
- PrintTypeBitmap(p, bitmaplen, buffer, length);
- }
- break;
- case kDNSType_RRSIG: {
- rdataRRSig *rrsig = (rdataRRSig *)rd->data;
- mDNSu8 expTimeBuf[64];
- mDNSu8 inceptTimeBuf[64];
- unsigned long inceptClock;
- unsigned long expClock;
- int len;
-
- expClock = (unsigned long)swap32(rrsig->sigExpireTime);
- mDNSPlatformFormatTime(expClock, expTimeBuf, sizeof(expTimeBuf));
-
- inceptClock = (unsigned long)swap32(rrsig->sigInceptTime);
- mDNSPlatformFormatTime(inceptClock, inceptTimeBuf, sizeof(inceptTimeBuf));
-
- length += mDNS_snprintf(buffer+length, RemSpc, "\t%s %s %d %d %s %s %d %##s ",
- DNSTypeName(swap16(rrsig->typeCovered)), DNSSECAlgName(rrsig->alg), rrsig->labels, swap32(rrsig->origTTL),
- expTimeBuf, inceptTimeBuf, swap16(rrsig->keyTag), rrsig->signerName);
-
- len = DomainNameLength((domainname *)&rrsig->signerName);
- baseEncode(buffer + length, RemSpc, (const mDNSu8 *)(rd->data + len + RRSIG_FIXED_SIZE),
- rr->rdlength - (len + RRSIG_FIXED_SIZE), ENC_BASE64);
- }
- break;
- case kDNSType_DNSKEY: {
- rdataDNSKey *rrkey = (rdataDNSKey *)rd->data;
- length += mDNS_snprintf(buffer+length, RemSpc, "\t%d %d %s %u ", swap16(rrkey->flags), rrkey->proto,
- DNSSECAlgName(rrkey->alg), (unsigned int)keytag((mDNSu8 *)rrkey, rr->rdlength));
- baseEncode(buffer + length, RemSpc, (const mDNSu8 *)(rd->data + DNSKEY_FIXED_SIZE),
- rr->rdlength - DNSKEY_FIXED_SIZE, ENC_BASE64);
- }
- break;
- case kDNSType_DS: {
- mDNSu8 *p;
- int i;
- rdataDS *rrds = (rdataDS *)rd->data;
-
- length += mDNS_snprintf(buffer+length, RemSpc, "\t%s\t%d\t%s ", DNSSECAlgName(rrds->alg), swap16(rrds->keyTag),
- DNSSECDigestName(rrds->digestType));
-
- p = (mDNSu8 *)(rd->data + DS_FIXED_SIZE);
- for (i = 0; i < (rr->rdlength - DS_FIXED_SIZE); i++)
- {
- length += mDNS_snprintf(buffer+length, RemSpc, "%x", p[i]);
- }
- }
- break;
default: mDNS_snprintf(buffer+length, RemSpc, "RDLen %d: %.*s", rr->rdlength, rr->rdlength, rd->data);
// Really should scan buffer to check if text is valid UTF-8 and only replace with dots if not
for (ptr = buffer; *ptr; ptr++) if (*ptr < ' ') *ptr = '.';
break;
}
+
return(buffer);
}
@@ -994,7 +850,7 @@ mDNSexport mDNSu8 *ConstructServiceName(domainname *const fqdn,
// In the case where there is no name (and ONLY in that case),
// a single-label subtype is allowed as the first label of a three-part "type"
- if (!name && type)
+ if (!name)
{
const mDNSu8 *s0 = type->c;
if (s0[0] && s0[0] < 0x40) // If legal first label (at least one character, and no more than 63)
@@ -1160,57 +1016,6 @@ mDNSexport mStatus DNSNameToLowerCase(domainname *d, domainname *result)
return mStatus_NoError;
}
-mDNSexport const mDNSu8 *NSEC3HashName(const domainname *name, rdataNSEC3 *nsec3, const mDNSu8 *AnonData, int AnonDataLen,
- const mDNSu8 hash[NSEC3_MAX_HASH_LEN], int *dlen)
-{
- AlgContext *ctx;
- unsigned int i;
- unsigned int iterations;
- domainname lname;
- mDNSu8 *p = (mDNSu8 *)&nsec3->salt;
- const mDNSu8 *digest;
- int digestlen;
- mDNSBool first = mDNStrue;
-
- if (DNSNameToLowerCase((domainname *)name, &lname) != mStatus_NoError)
- {
- LogMsg("NSEC3HashName: ERROR!! DNSNameToLowerCase failed");
- return mDNSNULL;
- }
-
- digest = lname.c;
- digestlen = DomainNameLength(&lname);
-
- // Note that it is "i <=". The first iteration is for digesting the name and salt.
- // The iteration count does not include that.
- iterations = swap16(nsec3->iterations);
- for (i = 0; i <= iterations; i++)
- {
- ctx = AlgCreate(DIGEST_ALG, nsec3->alg);
- if (!ctx)
- {
- LogMsg("NSEC3HashName: ERROR!! Cannot allocate context");
- return mDNSNULL;
- }
-
- AlgAdd(ctx, digest, digestlen);
- if (nsec3->saltLength)
- AlgAdd(ctx, p, nsec3->saltLength);
- if (AnonDataLen)
- AlgAdd(ctx, AnonData, AnonDataLen);
- if (first)
- {
- first = mDNSfalse;
- digest = hash;
- digestlen = AlgLength(ctx);
- }
- AlgFinal(ctx, (void *)digest, digestlen);
- AlgDestroy(ctx);
- }
- *dlen = digestlen;
- return digest;
-}
-
// Notes on UTF-8:
// 0xxxxxxx represents a 7-bit ASCII value from 0x00 to 0x7F
// 10xxxxxx is a continuation byte of a multi-byte character
@@ -1391,8 +1196,11 @@ mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mD
rr->resrec.rrtype = rrtype;
rr->resrec.rrclass = kDNSClass_IN;
rr->resrec.rroriginalttl = ttl;
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ rr->resrec.dnsservice = NULL;
+#else
rr->resrec.rDNSServer = mDNSNULL;
- rr->resrec.AnonInfo = mDNSNULL;
+#endif
// rr->resrec.rdlength = MUST set by client and/or in mDNS_Register_internal
// rr->resrec.rdestimate = set in mDNS_Register_internal
// rr->resrec.rdata = MUST be set by client
@@ -1456,7 +1264,6 @@ mDNSexport void mDNS_SetupQuestion(DNSQuestion *const q, const mDNSInterfaceID I
{
q->InterfaceID = InterfaceID;
q->flags = 0;
- q->Target = zeroAddr;
AssignDomainName(&q->qname, name);
q->qtype = qtype;
q->qclass = kDNSClass_IN;
@@ -1465,20 +1272,14 @@ mDNSexport void mDNS_SetupQuestion(DNSQuestion *const q, const mDNSInterfaceID I
q->ForceMCast = mDNSfalse;
q->ReturnIntermed = mDNSfalse;
q->SuppressUnusable = mDNSfalse;
- q->SearchListIndex = 0;
q->AppendSearchDomains = 0;
- q->RetryWithSearchDomains = mDNSfalse;
q->TimeoutQuestion = 0;
q->WakeOnResolve = 0;
- q->UseBackgroundTrafficClass = mDNSfalse;
- q->ValidationRequired = 0;
- q->ValidatingResponse = 0;
+ q->UseBackgroundTraffic = mDNSfalse;
q->ProxyQuestion = 0;
- q->qnameOrig = mDNSNULL;
- q->AnonInfo = mDNSNULL;
q->pid = mDNSPlatformGetPID();
q->euid = 0;
- q->DisallowPID = mDNSfalse;
+ q->BlockedByPolicy = mDNSfalse;
q->ServiceID = -1;
q->QuestionCallback = callback;
q->QuestionContext = context;
@@ -1532,6 +1333,7 @@ mDNSexport mDNSu32 RDataHashValue(const ResourceRecord *const rr)
sum = DomainNameHashValue((domainname *)rdb->data);
ptr += dlen;
len -= dlen;
+ /* FALLTHROUGH */
}
/* FALLTHROUGH */
@@ -1698,70 +1500,6 @@ mDNSexport mDNSBool RRAssertsNonexistence(const ResourceRecord *const rr, mDNSu1
return !RRAssertsExistence(rr, type);
}
-// Checks whether the RRSIG or NSEC record answers the question "q".
-mDNSlocal mDNSBool DNSSECRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q, mDNSBool *checkType)
-{
- *checkType = mDNStrue;
-
- // This function is called for all questions and as long as the type matches,
- // return true. For the types (RRSIG and NSEC) that are specifically checked in
- // this function, returning true still holds good.
- if (q->qtype == rr->rrtype)
- return mDNStrue;
-
- // For DS and DNSKEY questions, the types should match i.e., don't answer using CNAME
- // records as it answers any question type.
- //
- // - DS record comes from the parent zone where CNAME record cannot coexist and hence
- // cannot possibly answer it.
- //
- // - For DNSKEY, one could potentially follow CNAME but there could be a DNSKEY at
- // the "qname" itself. To keep it simple, we don't follow CNAME.
-
- if ((q->qtype == kDNSType_DS || q->qtype == kDNSType_DNSKEY) && (q->qtype != rr->rrtype))
- {
- debugf("DNSSECRecordAnswersQuestion: %d type resource record matched question %##s (%s), ignoring", rr->rrtype,
- q->qname.c, DNSTypeName(q->qtype));
- return mDNSfalse;
- }
-
- // If we are validating a response using DNSSEC, we might already have the records
- // for the "q->qtype" in the cache but we issued a query with DO bit set
- // to get the RRSIGs e.g., if you have two questions one of which does not require
- // DNSSEC validation. When the RRSIG is added to the cache, we need to deliver
- // the response to the question. The RRSIG type won't match the q->qtype and hence
- // we need to bypass the check in that case.
- if (rr->rrtype == kDNSType_RRSIG && q->ValidatingResponse)
- {
- const RDataBody2 *const rdb = (RDataBody2 *)rr->rdata->u.data;
- rdataRRSig *rrsig = (rdataRRSig *)rdb->data;
- mDNSu16 typeCovered = swap16(rrsig->typeCovered);
- debugf("DNSSECRecordAnswersQuestion: Matching RRSIG typeCovered %s", DNSTypeName(typeCovered));
- if (typeCovered != kDNSType_CNAME && typeCovered != q->qtype)
- {
- debugf("DNSSECRecordAnswersQuestion: RRSIG did not match question %##s (%s)", q->qname.c,
- DNSTypeName(q->qtype));
- return mDNSfalse;
- }
- LogInfo("DNSSECRecordAnswersQuestion: RRSIG matched question %##s (%s)", q->qname.c,
- DNSTypeName(q->qtype));
- *checkType = mDNSfalse;
- return mDNStrue;
- }
- // If the NSEC record asserts the non-existence of a name looked up by the question, we would
- // typically answer that e.g., the bitmap asserts that q->qtype does not exist. If we have
- // to prove the non-existence as required by ValidatingResponse and ValidationRequired question,
- // then we should not answer that as it may not be the right one always. We may need more than
- // one NSEC to prove the non-existence.
- if (rr->rrtype == kDNSType_NSEC && DNSSECQuestion(q))
- {
- debugf("DNSSECRecordAnswersQuestion: Question %##s (%s) matched record %##s (NSEC)", q->qname.c,
- DNSTypeName(q->qtype), rr->name->c);
- return mDNSfalse;
- }
- return mDNStrue;
-}
-
// ResourceRecordAnswersQuestion returns mDNStrue if the given resource record is a valid answer to the given question.
// SameNameRecordAnswersQuestion is the same, except it skips the expensive SameDomainName() call.
// SameDomainName() is generally cheap when the names don't match, but expensive when they do match,
@@ -1769,7 +1507,7 @@ mDNSlocal mDNSBool DNSSECRecordAnswersQuestion(const ResourceRecord *const rr, c
// In cases where we know in advance that the names match it's especially advantageous to skip the
// SameDomainName() call because that's precisely the time when it's most expensive and least useful.
-mDNSexport mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
+mDNSlocal mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr, mDNSBool isAuthRecord, const DNSQuestion *const q)
{
mDNSBool checkType = mDNStrue;
@@ -1780,7 +1518,7 @@ mDNSexport mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr
LogMsg("SameNameRecordAnswersQuestion: ERROR!! called with LocalOnly ResourceRecord %p, Question %p", rr->InterfaceID, q->InterfaceID);
return mDNSfalse;
}
- if (QuerySuppressed(q))
+ if (q->Suppressed)
return mDNSfalse;
if (rr->InterfaceID &&
@@ -1788,12 +1526,16 @@ mDNSexport mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr
rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
// Resource record received via unicast, the resolver group ID should match ?
- if (!rr->InterfaceID)
+ if (!isAuthRecord && !rr->InterfaceID)
{
- mDNSu16 idr = (rr->rDNSServer ? rr->rDNSServer->resGroupID : 0);
- mDNSu16 idq = (q->qDNSServer ? q->qDNSServer->resGroupID : 0);
+ if (mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse);
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ if (rr->dnsservice != q->dnsservice) return(mDNSfalse);
+#else
+ const mDNSu32 idr = rr->rDNSServer ? rr->rDNSServer->resGroupID : 0;
+ const mDNSu32 idq = q->qDNSServer ? q->qDNSServer->resGroupID : 0;
if (idr != idq) return(mDNSfalse);
- if (!DNSSECRecordAnswersQuestion(rr, q, &checkType)) return mDNSfalse;
+#endif
}
// If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question
@@ -1802,7 +1544,11 @@ mDNSexport mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr
// CNAME answers question of any type and a negative cache record should not prevent us from querying other
// valid types at the same name.
if (rr->rrtype == kDNSType_CNAME && rr->RecordType == kDNSRecordTypePacketNegative && rr->rrtype != q->qtype)
- return mDNSfalse;
+ return mDNSfalse;
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+ if (enables_dnssec_validation(q) && record_type_answers_dnssec_question(rr, q->qtype)) checkType = mDNSfalse;
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
// RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class.
if (checkType && !RRTypeAnswersQuestionType(rr,q->qtype)) return(mDNSfalse);
@@ -1813,20 +1559,37 @@ mDNSexport mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr
return mDNSfalse;
#endif // APPLE_OSX_mDNSResponder
- if (!AnonInfoAnswersQuestion(rr, q))
- return mDNSfalse;
-
return(mDNStrue);
}
-mDNSexport mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
+mDNSexport mDNSBool SameNameCacheRecordAnswersQuestion(const CacheRecord *const cr, const DNSQuestion *const q)
+{
+ return SameNameRecordAnswersQuestion(&cr->resrec, mDNSfalse, q);
+}
+
+mDNSlocal mDNSBool RecordAnswersQuestion(const ResourceRecord *const rr, mDNSBool isAuthRecord, const DNSQuestion *const q)
{
- if (!SameNameRecordAnswersQuestion(rr, q))
+ if (!SameNameRecordAnswersQuestion(rr, isAuthRecord, q))
return mDNSfalse;
return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname));
}
+mDNSexport mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
+{
+ return RecordAnswersQuestion(rr, mDNSfalse, q);
+}
+
+mDNSexport mDNSBool AuthRecordAnswersQuestion(const AuthRecord *const ar, const DNSQuestion *const q)
+{
+ return RecordAnswersQuestion(&ar->resrec, mDNStrue, q);
+}
+
+mDNSexport mDNSBool CacheRecordAnswersQuestion(const CacheRecord *const cr, const DNSQuestion *const q)
+{
+ return RecordAnswersQuestion(&cr->resrec, mDNSfalse, q);
+}
+
// We have a separate function to handle LocalOnly AuthRecords because they can be created with
// a valid InterfaceID (e.g., scoped /etc/hosts) and can be used to answer unicast questions unlike
// multicast resource records (which has a valid InterfaceID) which can't be used to answer
@@ -1852,12 +1615,11 @@ mDNSexport mDNSBool LocalOnlyRecordAnswersQuestion(AuthRecord *const ar, const D
// *local* to the machine. These include resource records that have InterfaceID set to mDNSInterface_LocalOnly,
// mDNSInterface_Any and any other real InterfaceID. Hence, LocalOnly questions should not be checked against
// the InterfaceID in the resource record.
- //
- // mDNSInterface_Unicast does not indicate any scope and hence treat them like mDNSInterface_Any.
if (rr->InterfaceID &&
- q->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly && q->InterfaceID != mDNSInterface_Unicast &&
- rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
+ q->InterfaceID != mDNSInterface_LocalOnly &&
+ ((q->InterfaceID && rr->InterfaceID != q->InterfaceID) ||
+ (!q->InterfaceID && !LocalOnlyOrP2PInterface(rr->InterfaceID)))) return(mDNSfalse);
// Entries in /etc/hosts are added as LocalOnly resource records. The LocalOnly resource records
// may have a scope e.g., fe80::1%en0. The question may be scoped or not: the InterfaceID may be set
@@ -1900,14 +1662,12 @@ mDNSexport mDNSBool LocalOnlyRecordAnswersQuestion(AuthRecord *const ar, const D
if (!RRTypeAnswersQuestionType(rr,q->qtype)) return(mDNSfalse);
if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse);
- if (!AnonInfoAnswersQuestion(rr, q))
- return mDNSfalse;
-
return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname));
}
-mDNSexport mDNSBool AnyTypeRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
+mDNSexport mDNSBool AnyTypeRecordAnswersQuestion(const AuthRecord *const ar, const DNSQuestion *const q)
{
+ const ResourceRecord *const rr = &ar->resrec;
// LocalOnly/P2P questions can be answered with AuthRecordAny in this function. LocalOnly/P2P records
// are handled in LocalOnlyRecordAnswersQuestion
if (LocalOnlyOrP2PInterface(rr->InterfaceID))
@@ -1924,9 +1684,16 @@ mDNSexport mDNSBool AnyTypeRecordAnswersQuestion(const ResourceRecord *const rr,
// both the DNSServers are assumed to be NULL in that case
if (!rr->InterfaceID)
{
- mDNSu16 idr = (rr->rDNSServer ? rr->rDNSServer->resGroupID : 0);
- mDNSu16 idq = (q->qDNSServer ? q->qDNSServer->resGroupID : 0);
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ if (rr->dnsservice != q->dnsservice) return(mDNSfalse);
+#else
+ const mDNSu32 idr = rr->rDNSServer ? rr->rDNSServer->resGroupID : 0;
+ const mDNSu32 idq = q->qDNSServer ? q->qDNSServer->resGroupID : 0;
if (idr != idq) return(mDNSfalse);
+#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ if (!mDNSPlatformValidRecordForInterface(ar, q->InterfaceID)) return(mDNSfalse);
+#endif
}
// If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question
@@ -1934,9 +1701,6 @@ mDNSexport mDNSBool AnyTypeRecordAnswersQuestion(const ResourceRecord *const rr,
if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse);
- if (!AnonInfoAnswersQuestion(rr, q))
- return mDNSfalse;
-
return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname));
}
@@ -1949,7 +1713,7 @@ mDNSexport mDNSBool ResourceRecordAnswersUnicastResponse(const ResourceRecord *c
{
mDNSBool checkType = mDNStrue;
- if (QuerySuppressed(q))
+ if (q->Suppressed)
return mDNSfalse;
// For resource records created using multicast, the InterfaceIDs have to match
@@ -1959,7 +1723,9 @@ mDNSexport mDNSBool ResourceRecordAnswersUnicastResponse(const ResourceRecord *c
// If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question.
if (rr->InterfaceID && !mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse);
- if (!DNSSECRecordAnswersQuestion(rr, q, &checkType)) return mDNSfalse;
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+ if (enables_dnssec_validation(q) && record_type_answers_dnssec_question(rr, q->qtype)) checkType = mDNSfalse;
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
// RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class.
if (checkType && !RRTypeAnswersQuestionType(rr,q->qtype)) return(mDNSfalse);
@@ -2002,6 +1768,7 @@ mDNSexport mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate
case kDNSType_RT:
case kDNSType_KX: return (mDNSu16)(2 + CompressedDomainNameLength(&rd->mx.exchange, name));
+ case kDNSType_MINFO:
case kDNSType_RP: return (mDNSu16)(CompressedDomainNameLength(&rd->rp.mbox, name) +
CompressedDomainNameLength(&rd->rp.txt, name));
@@ -2096,6 +1863,8 @@ mDNSexport void InitializeDNSMessage(DNSMessageHeader *h, mDNSOpaque16 id, mDNSO
h->numAdditionals = 0;
}
+#endif // !STANDALONE
+
mDNSexport const mDNSu8 *FindCompressionPointer(const mDNSu8 *const base, const mDNSu8 *const end, const mDNSu8 *const domname)
{
const mDNSu8 *result = end - *domname - 1;
@@ -2202,6 +1971,8 @@ mDNSexport mDNSu8 *putDomainNameAsLabels(const DNSMessage *const msg,
return(ptr);
}
+#ifndef STANDALONE
+
mDNSlocal mDNSu8 *putVal16(mDNSu8 *ptr, mDNSu16 val)
{
ptr[0] = (mDNSu8)((val >> 8 ) & 0xFF);
@@ -2433,7 +2204,8 @@ mDNSexport mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNS
#define IsUnicastUpdate(X) (!mDNSOpaque16IsZero((X)->h.id) && ((X)->h.flags.b[0] & kDNSFlag0_OP_Mask) == kDNSFlag0_OP_Update)
-mDNSexport mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, ResourceRecord *rr, mDNSu32 ttl, const mDNSu8 *limit)
+mDNSexport mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count,
+ const ResourceRecord *rr, mDNSu32 ttl, const mDNSu8 *limit)
{
mDNSu8 *endofrdata;
mDNSu16 actualLength;
@@ -2442,13 +2214,17 @@ mDNSexport mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *
if (rr->RecordType == kDNSRecordTypeUnregistered)
{
- LogMsg("PutResourceRecordTTLWithLimit ERROR! Attempt to put kDNSRecordTypeUnregistered %##s (%s)", rr->name->c, DNSTypeName(rr->rrtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "Attempt to put kDNSRecordTypeUnregistered " PRI_DM_NAME " (" PUB_S ")",
+ DM_NAME_PARAM(rr->name), DNSTypeName(rr->rrtype));
return(ptr);
}
if (!ptr)
{
- LogMsg("PutResourceRecordTTLWithLimit ptr is null %##s (%s)", rr->name->c, DNSTypeName(rr->rrtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "Pointer to message is NULL while filling resource record " PRI_DM_NAME " (" PUB_S ")",
+ DM_NAME_PARAM(rr->name), DNSTypeName(rr->rrtype));
return(mDNSNULL);
}
@@ -2456,8 +2232,10 @@ mDNSexport mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *
// If we're out-of-space, return mDNSNULL
if (!ptr || ptr + 10 >= limit)
{
- LogInfo("PutResourceRecordTTLWithLimit: can't put name, out of space %##s (%s), ptr %p, limit %p", rr->name->c,
- DNSTypeName(rr->rrtype), ptr, limit);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+ "Can't put more names into current message, will possibly put it into the next message - "
+ "name: " PRI_DM_NAME " (" PUB_S "), remaining space: %ld",
+ DM_NAME_PARAM(rr->name), DNSTypeName(rr->rrtype), (long)(limit - ptr));
return(mDNSNULL);
}
ptr[0] = (mDNSu8)(rr->rrtype >> 8);
@@ -2473,8 +2251,10 @@ mDNSexport mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *
endofrdata = putRData(rdatacompressionbase, ptr+10, limit, rr);
if (!endofrdata)
{
- LogInfo("PutResourceRecordTTLWithLimit: Ran out of space in PutResourceRecord for %##s (%s), ptr %p, limit %p", rr->name->c,
- DNSTypeName(rr->rrtype), ptr+10, limit);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+ "Can't put more rdata into current message, will possibly put it into the next message - "
+ "name: " PRI_DM_NAME " (" PUB_S "), remaining space: %ld",
+ DM_NAME_PARAM(rr->name), DNSTypeName(rr->rrtype), (long)(limit - ptr - 10));
return(mDNSNULL);
}
@@ -2484,8 +2264,16 @@ mDNSexport mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *
ptr[8] = (mDNSu8)(actualLength >> 8);
ptr[9] = (mDNSu8)(actualLength & 0xFF);
- if (count) (*count)++;
- else LogMsg("PutResourceRecordTTL: ERROR: No target count to update for %##s (%s)", rr->name->c, DNSTypeName(rr->rrtype));
+ if (count)
+ {
+ (*count)++;
+ }
+ else
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "No target count to update for " PRI_DM_NAME " (" PUB_S ")",
+ DM_NAME_PARAM(rr->name), DNSTypeName(rr->rrtype));
+ }
return(endofrdata);
}
@@ -2628,48 +2416,6 @@ mDNSexport mDNSu8 *putUpdateLeaseWithLimit(DNSMessage *msg, mDNSu8 *ptr, mDNSu32
return ptr;
}
-mDNSexport mDNSu8 *putDNSSECOption(DNSMessage *msg, mDNSu8 *end, mDNSu8 *limit)
-{
- AuthRecord rr;
- mDNSu32 ttl = 0;
-
- mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
- // It is still not clear what the right size is. We will have to fine tune this once we do
- // a lot of testing with DNSSEC.
- rr.resrec.rrclass = 4096;
- rr.resrec.rdlength = 0;
- rr.resrec.rdestimate = 0;
- // set the DO bit
- ttl |= 0x8000;
- end = PutResourceRecordTTLWithLimit(msg, end, &msg->h.numAdditionals, &rr.resrec, ttl, limit);
- if (!end) { LogMsg("ERROR: putDNSSECOption - PutResourceRecordTTLWithLimit"); return mDNSNULL; }
- return end;
-}
-
-mDNSexport mDNSu8 *putHINFO(const mDNS *const m, DNSMessage *const msg, mDNSu8 *end, DomainAuthInfo *authInfo, mDNSu8 *limit)
-{
- if (authInfo && authInfo->AutoTunnel)
- {
- AuthRecord hinfo;
- mDNSu8 *h = hinfo.rdatastorage.u.data;
- mDNSu16 len = 2 + m->HIHardware.c[0] + m->HISoftware.c[0];
- mDNSu8 *newptr;
- mDNS_SetupResourceRecord(&hinfo, mDNSNULL, mDNSInterface_Any, kDNSType_HINFO, 0, kDNSRecordTypeUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
- AppendDomainLabel(&hinfo.namestorage, &m->hostlabel);
- AppendDomainName (&hinfo.namestorage, &authInfo->domain);
- hinfo.resrec.rroriginalttl = 0;
- mDNSPlatformMemCopy(h, &m->HIHardware, 1 + (mDNSu32)m->HIHardware.c[0]);
- h += 1 + (int)h[0];
- mDNSPlatformMemCopy(h, &m->HISoftware, 1 + (mDNSu32)m->HISoftware.c[0]);
- hinfo.resrec.rdlength = len;
- hinfo.resrec.rdestimate = len;
- newptr = PutResourceRecordTTLWithLimit(msg, end, &msg->h.numAdditionals, &hinfo.resrec, 0, limit);
- return newptr;
- }
- else
- return end;
-}
-
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
@@ -2835,20 +2581,34 @@ mDNSlocal mDNSu8 *SanityCheckBitMap(const mDNSu8 *bmap, const mDNSu8 *end, int l
return (mDNSu8 *)bmap;
}
+mDNSlocal mDNSBool AssignDomainNameWithLimit(domainname *const dst, const domainname *src, const mDNSu8 *const end)
+{
+ const mDNSu32 len = DomainNameLengthLimit(src, end);
+ if ((len >= 1) && (len <= MAX_DOMAIN_NAME))
+ {
+ mDNSPlatformMemCopy(dst->c, src->c, len);
+ return mDNStrue;
+ }
+ else
+ {
+ dst->c[0] = 0;
+ return mDNSfalse;
+ }
+}
+
// This function is called with "msg" when we receive a DNS message and needs to parse a single resource record
// pointed to by "ptr". Some resource records like SOA, SRV are converted to host order and also expanded
-// (domainnames are expanded to 255 bytes) when stored in memory.
+// (domainnames are expanded to 256 bytes) when stored in memory.
//
// This function can also be called with "NULL" msg to parse a single resource record pointed to by ptr.
// The caller can do this only if the names in the resource records are not compressed and validity of the
-// resource record has already been done before. DNSSEC currently uses it this way.
-mDNSexport mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *end,
- LargeCacheRecord *const largecr, mDNSu16 rdlength)
+// resource record has already been done before.
+mDNSexport mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *end, ResourceRecord *const rr,
+ const mDNSu16 rdlength)
{
- CacheRecord *const rr = &largecr->r;
- RDataBody2 *const rdb = (RDataBody2 *)rr->smallrdatastorage.data;
+ RDataBody2 *const rdb = (RDataBody2 *)&rr->rdata->u;
- switch (rr->resrec.rrtype)
+ switch (rr->rrtype)
{
case kDNSType_A:
if (rdlength != sizeof(mDNSv4Addr))
@@ -2875,7 +2635,10 @@ mDNSexport mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, con
}
else
{
- AssignDomainName(&rdb->name, (domainname *)ptr);
+ if (!AssignDomainNameWithLimit(&rdb->name, (domainname *)ptr, end))
+ {
+ goto fail;
+ }
ptr += DomainNameLength(&rdb->name);
}
if (ptr != end)
@@ -2892,7 +2655,10 @@ mDNSexport mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, con
}
else
{
- AssignDomainName(&rdb->soa.mname, (domainname *)ptr);
+ if (!AssignDomainNameWithLimit(&rdb->soa.mname, (domainname *)ptr, end))
+ {
+ goto fail;
+ }
ptr += DomainNameLength(&rdb->soa.mname);
}
if (!ptr)
@@ -2906,7 +2672,10 @@ mDNSexport mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, con
}
else
{
- AssignDomainName(&rdb->soa.rname, (domainname *)ptr);
+ if (!AssignDomainNameWithLimit(&rdb->soa.rname, (domainname *)ptr, end))
+ {
+ goto fail;
+ }
ptr += DomainNameLength(&rdb->soa.rname);
}
if (!ptr)
@@ -2926,14 +2695,51 @@ mDNSexport mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, con
rdb->soa.min = (mDNSu32) ((mDNSu32)ptr[0x10] << 24 | (mDNSu32)ptr[0x11] << 16 | (mDNSu32)ptr[0x12] << 8 | ptr[0x13]);
break;
- case kDNSType_NULL:
case kDNSType_HINFO:
+ // See https://tools.ietf.org/html/rfc1035#section-3.3.2 for HINFO RDATA format.
+ {
+ // HINFO should contain RDATA.
+ if (end <= ptr || rdlength != (mDNSu32)(end - ptr))
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+ "SetRData: Malformed HINFO RDATA - invalid RDATA length: %u", rdlength);
+ goto fail;
+ }
+
+ const mDNSu8 *currentPtr = ptr;
+ // CPU character string length should be less than the RDATA length.
+ mDNSu32 cpuCharacterStrLength = currentPtr[0];
+ if (1 + cpuCharacterStrLength >= (mDNSu32)(end - currentPtr))
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+ "SetRData: Malformed HINFO RDATA - CPU character string goes out of boundary");
+ goto fail;
+ }
+ currentPtr += 1 + cpuCharacterStrLength;
+
+ // OS character string should end at the RDATA ending.
+ mDNSu32 osCharacterStrLength = currentPtr[0];
+ if (1 + osCharacterStrLength != (mDNSu32)(end - currentPtr))
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+ "SetRData: Malformed HINFO RDATA - OS character string does not end at the RDATA ending");
+ goto fail;
+ }
+
+ // Copy the validated RDATA.
+ rr->rdlength = rdlength;
+ mDNSPlatformMemCopy(rdb->data, ptr, rdlength);
+ break;
+ }
+ case kDNSType_NULL:
case kDNSType_TXT:
case kDNSType_X25:
case kDNSType_ISDN:
case kDNSType_LOC:
case kDNSType_DHCID:
- rr->resrec.rdlength = rdlength;
+ case kDNSType_SVCB:
+ case kDNSType_HTTPS:
+ rr->rdlength = rdlength;
mDNSPlatformMemCopy(rdb->data, ptr, rdlength);
break;
@@ -2952,7 +2758,10 @@ mDNSexport mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, con
}
else
{
- AssignDomainName(&rdb->mx.exchange, (domainname *)ptr);
+ if (!AssignDomainNameWithLimit(&rdb->mx.exchange, (domainname *)ptr, end))
+ {
+ goto fail;
+ }
ptr += DomainNameLength(&rdb->mx.exchange);
}
if (ptr != end)
@@ -2971,7 +2780,10 @@ mDNSexport mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, con
}
else
{
- AssignDomainName(&rdb->rp.mbox, (domainname *)ptr);
+ if (!AssignDomainNameWithLimit(&rdb->rp.mbox, (domainname *)ptr, end))
+ {
+ goto fail;
+ }
ptr += DomainNameLength(&rdb->rp.mbox);
}
if (!ptr)
@@ -2985,7 +2797,10 @@ mDNSexport mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, con
}
else
{
- AssignDomainName(&rdb->rp.txt, (domainname *)ptr);
+ if (!AssignDomainNameWithLimit(&rdb->rp.txt, (domainname *)ptr, end))
+ {
+ goto fail;
+ }
ptr += DomainNameLength(&rdb->rp.txt);
}
if (ptr != end)
@@ -3007,7 +2822,10 @@ mDNSexport mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, con
}
else
{
- AssignDomainName(&rdb->px.map822, (domainname *)ptr);
+ if (!AssignDomainNameWithLimit(&rdb->px.map822, (domainname *)ptr, end))
+ {
+ goto fail;
+ }
ptr += DomainNameLength(&rdb->px.map822);
}
if (!ptr)
@@ -3021,7 +2839,10 @@ mDNSexport mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, con
}
else
{
- AssignDomainName(&rdb->px.mapx400, (domainname *)ptr);
+ if (!AssignDomainNameWithLimit(&rdb->px.mapx400, (domainname *)ptr, end))
+ {
+ goto fail;
+ }
ptr += DomainNameLength(&rdb->px.mapx400);
}
if (ptr != end)
@@ -3052,7 +2873,10 @@ mDNSexport mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, con
}
else
{
- AssignDomainName(&rdb->srv.target, (domainname *)ptr);
+ if (!AssignDomainNameWithLimit(&rdb->srv.target, (domainname *)ptr, end))
+ {
+ goto fail;
+ }
ptr += DomainNameLength(&rdb->srv.target);
}
if (ptr != end)
@@ -3068,8 +2892,7 @@ mDNSexport mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, con
domainname name;
const mDNSu8 *orig = ptr;
- // Make sure the data is parseable and within the limits. DNSSEC code looks at
- // the domain name in the end for a valid domainname.
+ // Make sure the data is parseable and within the limits.
//
// Fixed length: Order, preference (4 bytes)
// Variable length: flags, service, regexp, domainname
@@ -3106,7 +2929,7 @@ mDNSexport mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, con
goto fail;
}
- savelen = ptr - orig;
+ savelen = (int)(ptr - orig);
// RFC 2915 states that name compression is not allowed for this field. But RFC 3597
// states that for NAPTR we should decompress. We make sure that we store the full
@@ -3117,7 +2940,10 @@ mDNSexport mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, con
}
else
{
- AssignDomainName(&name, (domainname *)ptr);
+ if (!AssignDomainNameWithLimit(&name, (domainname *)ptr, end))
+ {
+ goto fail;
+ }
ptr += DomainNameLength(&name);
}
if (ptr != end)
@@ -3126,12 +2952,12 @@ mDNSexport mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, con
goto fail;
}
- rr->resrec.rdlength = savelen + DomainNameLength(&name);
+ rr->rdlength = savelen + DomainNameLength(&name);
// The uncompressed size should not exceed the limits
- if (rr->resrec.rdlength > MaximumRDSize)
+ if (rr->rdlength > MaximumRDSize)
{
- LogInfo("SetRData: Malformed NAPTR rdlength %d, rr->resrec.rdlength %d, "
- "bmaplen %d, name %##s", rdlength, rr->resrec.rdlength, name.c);
+ LogInfo("SetRData: Malformed NAPTR rdlength %d, rr->rdlength %d, "
+ "bmaplen %d, name %##s", rdlength, rr->rdlength, name.c);
goto fail;
}
mDNSPlatformMemCopy(rdb->data, orig, savelen);
@@ -3139,10 +2965,10 @@ mDNSexport mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, con
break;
}
case kDNSType_OPT: {
- mDNSu8 *dataend = rr->resrec.rdata->u.data;
- rdataOPT *opt = rr->resrec.rdata->u.opt;
- rr->resrec.rdlength = 0;
- while (ptr < end && (mDNSu8 *)(opt+1) < &dataend[MaximumRDSize])
+ const mDNSu8 * const dataend = &rr->rdata->u.data[rr->rdata->MaxRDLength];
+ rdataOPT *opt = rr->rdata->u.opt;
+ rr->rdlength = 0;
+ while ((ptr < end) && ((dataend - ((const mDNSu8 *)opt)) >= ((mDNSs32)sizeof(*opt))))
{
const rdataOPT *const currentopt = opt;
if (ptr + 4 > end) { LogInfo("SetRData: OPT RDATA ptr + 4 > end"); goto fail; }
@@ -3210,7 +3036,7 @@ mDNSexport mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, con
}
ptr += currentopt->optlen;
}
- rr->resrec.rdlength = (mDNSu16)((mDNSu8*)opt - rr->resrec.rdata->u.data);
+ rr->rdlength = (mDNSu16)((mDNSu8*)opt - rr->rdata->u.data);
if (ptr != end) { LogInfo("SetRData: Malformed OptRdata"); goto fail; }
break;
}
@@ -3228,7 +3054,10 @@ mDNSexport mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, con
}
else
{
- AssignDomainName(&name, (domainname *)ptr);
+ if (!AssignDomainNameWithLimit(&name, (domainname *)ptr, end))
+ {
+ goto fail;
+ }
ptr += DomainNameLength(&name);
}
if (!ptr)
@@ -3257,69 +3086,19 @@ mDNSexport mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, con
// Initialize the right length here. When we call SetNewRData below which in turn calls
// GetRDLength and for NSEC case, it assumes that rdlength is intitialized
- rr->resrec.rdlength = DomainNameLength(&name) + bmaplen;
+ rr->rdlength = DomainNameLength(&name) + bmaplen;
// Do we have space after the name expansion ?
- if (rr->resrec.rdlength > MaximumRDSize)
+ if (rr->rdlength > MaximumRDSize)
{
- LogInfo("SetRData: Malformed NSEC rdlength %d, rr->resrec.rdlength %d, "
- "bmaplen %d, name %##s", rdlength, rr->resrec.rdlength, name.c);
+ LogInfo("SetRData: Malformed NSEC rdlength %d, rr->rdlength %d, "
+ "bmaplen %d, name %##s", rdlength, rr->rdlength, name.c);
goto fail;
}
AssignDomainName((domainname *)rdb->data, &name);
mDNSPlatformMemCopy(rdb->data + dlen, bmap, bmaplen);
break;
}
- case kDNSType_NSEC3:
- {
- rdataNSEC3 *nsec3 = (rdataNSEC3 *)ptr;
- mDNSu8 *p = (mDNSu8 *)&nsec3->salt;
- int hashLength, bitmaplen;
-
- if (rdlength < NSEC3_FIXED_SIZE + 1)
- {
- LogInfo("SetRData: NSEC3 too small length %d", rdlength);
- goto fail;
- }
- if (nsec3->alg != SHA1_DIGEST_TYPE)
- {
- LogInfo("SetRData: nsec3 alg %d not supported", nsec3->alg);
- goto fail;
- }
- if (swap16(nsec3->iterations) > NSEC3_MAX_ITERATIONS)
- {
- LogInfo("SetRData: nsec3 iteration count %d too big", swap16(nsec3->iterations));
- goto fail;
- }
- p += nsec3->saltLength;
- // There should at least be one byte beyond saltLength
- if (p >= end)
- {
- LogInfo("SetRData: nsec3 too small, at saltlength %d, p %p, end %p", nsec3->saltLength, p, end);
- goto fail;
- }
- // p is pointing at hashLength
- hashLength = (int)*p++;
- if (!hashLength)
- {
- LogInfo("SetRData: hashLength zero");
- goto fail;
- }
- p += hashLength;
- if (p > end)
- {
- LogInfo("SetRData: nsec3 too small, at hashLength %d, p %p, end %p", hashLength, p, end);
- goto fail;
- }
-
- bitmaplen = rdlength - (int)(p - ptr);
- p = SanityCheckBitMap(p, end, bitmaplen);
- if (!p)
- goto fail;
- rr->resrec.rdlength = rdlength;
- mDNSPlatformMemCopy(rdb->data, ptr, rdlength);
- break;
- }
case kDNSType_TKEY:
case kDNSType_TSIG:
{
@@ -3334,98 +3113,39 @@ mDNSexport mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, con
}
else
{
- AssignDomainName(&name, (domainname *)ptr);
+ if (!AssignDomainNameWithLimit(&name, (domainname *)ptr, end))
+ {
+ goto fail;
+ }
ptr += DomainNameLength(&name);
}
if (!ptr || ptr >= end)
{
- LogInfo("SetRData: Malformed name for TSIG/TKEY type %d", rr->resrec.rrtype);
+ LogInfo("SetRData: Malformed name for TSIG/TKEY type %d", rr->rrtype);
goto fail;
}
dlen = DomainNameLength(&name);
- rlen = end - ptr;
- rr->resrec.rdlength = dlen + rlen;
- if (rr->resrec.rdlength > MaximumRDSize)
+ rlen = (int)(end - ptr);
+ rr->rdlength = dlen + rlen;
+ if (rr->rdlength > MaximumRDSize)
{
- LogInfo("SetRData: Malformed TSIG/TKEY rdlength %d, rr->resrec.rdlength %d, "
- "bmaplen %d, name %##s", rdlength, rr->resrec.rdlength, name.c);
+ LogInfo("SetRData: Malformed TSIG/TKEY rdlength %d, rr->rdlength %d, "
+ "bmaplen %d, name %##s", rdlength, rr->rdlength, name.c);
goto fail;
}
AssignDomainName((domainname *)rdb->data, &name);
mDNSPlatformMemCopy(rdb->data + dlen, ptr, rlen);
break;
}
- case kDNSType_RRSIG:
- {
- const mDNSu8 *sig = ptr + RRSIG_FIXED_SIZE;
- const mDNSu8 *orig = sig;
- domainname name;
- if (rdlength < RRSIG_FIXED_SIZE + 1)
- {
- LogInfo("SetRData: RRSIG too small length %d", rdlength);
- goto fail;
- }
- if (msg)
- {
- sig = getDomainName(msg, sig, end, &name);
- }
- else
- {
- AssignDomainName(&name, (domainname *)sig);
- sig += DomainNameLength(&name);
- }
- if (!sig)
- {
- LogInfo("SetRData: Malformed RRSIG record");
- goto fail;
- }
-
- if ((sig - orig) != DomainNameLength(&name))
- {
- LogInfo("SetRData: Malformed RRSIG record, signer name compression");
- goto fail;
- }
- // Just ensure that we have at least one byte of the signature
- if (sig + 1 >= end)
- {
- LogInfo("SetRData: Not enough bytes for signature type %d", rr->resrec.rrtype);
- goto fail;
- }
- rr->resrec.rdlength = rdlength;
- mDNSPlatformMemCopy(rdb->data, ptr, rdlength);
- break;
- }
- case kDNSType_DNSKEY:
- {
- if (rdlength < DNSKEY_FIXED_SIZE + 1)
- {
- LogInfo("SetRData: DNSKEY too small length %d", rdlength);
- goto fail;
- }
- rr->resrec.rdlength = rdlength;
- mDNSPlatformMemCopy(rdb->data, ptr, rdlength);
- break;
- }
- case kDNSType_DS:
- {
- if (rdlength < DS_FIXED_SIZE + 1)
- {
- LogInfo("SetRData: DS too small length %d", rdlength);
- goto fail;
- }
- rr->resrec.rdlength = rdlength;
- mDNSPlatformMemCopy(rdb->data, ptr, rdlength);
- break;
- }
default:
debugf("SetRData: Warning! Reading resource type %d (%s) as opaque data",
- rr->resrec.rrtype, DNSTypeName(rr->resrec.rrtype));
+ rr->rrtype, DNSTypeName(rr->rrtype));
// Note: Just because we don't understand the record type, that doesn't
// mean we fail. The DNS protocol specifies rdlength, so we can
// safely skip over unknown records and ignore them.
// We also grab a binary copy of the rdata anyway, since the caller
// might know how to interpret it even if we don't.
- rr->resrec.rdlength = rdlength;
+ rr->rdlength = rdlength;
mDNSPlatformMemCopy(rdb->data, ptr, rdlength);
break;
}
@@ -3439,6 +3159,7 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
{
CacheRecord *const rr = &largecr->r;
mDNSu16 pktrdlength;
+ mDNSu32 maxttl = (!InterfaceID) ? mDNSMaximumUnicastTTLSeconds : mDNSMaximumMulticastTTLSeconds;
if (largecr == &m->rec && m->rec.r.resrec.RecordType)
LogFatalError("GetLargeResourceRecord: m->rec appears to be already in use for %s", CRDisplayString(m, &m->rec.r));
@@ -3450,13 +3171,20 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
rr->TimeRcvd = m ? m->timenow : 0;
rr->DelayDelivery = 0;
rr->NextRequiredQuery = m ? m->timenow : 0; // Will be updated to the real value when we call SetNextCacheCheckTimeForRecord()
+#if MDNSRESPONDER_SUPPORTS(APPLE, CACHE_ANALYTICS)
+ rr->LastCachedAnswerTime = 0;
+#endif
rr->CRActiveQuestion = mDNSNULL;
rr->UnansweredQueries = 0;
rr->LastUnansweredTime= 0;
rr->NextInCFList = mDNSNULL;
rr->resrec.InterfaceID = InterfaceID;
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ mdns_forget(&rr->resrec.dnsservice);
+#else
rr->resrec.rDNSServer = mDNSNULL;
+#endif
ptr = getDomainName(msg, ptr, end, &largecr->namestorage); // Will bail out correctly if ptr is NULL
if (!ptr) { debugf("GetLargeResourceRecord: Malformed RR name"); return(mDNSNULL); }
@@ -3467,8 +3195,8 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
rr->resrec.rrtype = (mDNSu16) ((mDNSu16)ptr[0] << 8 | ptr[1]);
rr->resrec.rrclass = (mDNSu16)(((mDNSu16)ptr[2] << 8 | ptr[3]) & kDNSClass_Mask);
rr->resrec.rroriginalttl = (mDNSu32) ((mDNSu32)ptr[4] << 24 | (mDNSu32)ptr[5] << 16 | (mDNSu32)ptr[6] << 8 | ptr[7]);
- if (rr->resrec.rroriginalttl > mDNSMaximumTTLSeconds && (mDNSs32)rr->resrec.rroriginalttl != -1)
- rr->resrec.rroriginalttl = mDNSMaximumTTLSeconds;
+ if (rr->resrec.rroriginalttl > maxttl && (mDNSs32)rr->resrec.rroriginalttl != -1)
+ rr->resrec.rroriginalttl = maxttl;
// Note: We don't have to adjust m->NextCacheCheck here -- this is just getting a record into memory for
// us to look at. If we decide to copy it into the cache, then we'll update m->NextCacheCheck accordingly.
pktrdlength = (mDNSu16)((mDNSu16)ptr[8] << 8 | ptr[9]);
@@ -3500,8 +3228,13 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
// two domainnames are different when semantically they are the same name and it's only the unused bytes that differ.
if (rr->resrec.rrclass == kDNSQClass_ANY && pktrdlength == 0) // Used in update packets to mean "Delete An RRset" (RFC 2136)
rr->resrec.rdlength = 0;
- else if (!SetRData(msg, ptr, end, largecr, pktrdlength))
+ else if (!SetRData(msg, ptr, end, &rr->resrec, pktrdlength))
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "GetLargeResourceRecord: SetRData failed for " PRI_DM_NAME " (" PUB_S ")",
+ DM_NAME_PARAM(rr->resrec.name), DNSTypeName(rr->resrec.rrtype));
goto fail;
+ }
SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rdlength, rdestimate, rdatahash for us
@@ -3636,23 +3369,23 @@ mDNSexport mDNSBool GetPktLease(mDNS *const m, const DNSMessage *const msg, cons
(X) == kDNSFlag0_OP_Unused3 ? "Unused3 " : \
(X) == kDNSFlag0_OP_Notify ? "Notify " : \
(X) == kDNSFlag0_OP_Update ? "Update " : \
- (X) == kDNSFlag0_OP_Subscribe? "Subscribe": \
- (X) == kDNSFlag0_OP_UnSubscribe? "UnSubscribe" : "?? " )
+ (X) == kDNSFlag0_OP_DSO ? "DSO " : "?? " )
#define DNS_RC_Name(X) ( \
- (X) == kDNSFlag1_RC_NoErr ? "NoErr" : \
- (X) == kDNSFlag1_RC_FormErr ? "FormErr" : \
- (X) == kDNSFlag1_RC_ServFail ? "ServFail" : \
- (X) == kDNSFlag1_RC_NXDomain ? "NXDomain" : \
- (X) == kDNSFlag1_RC_NotImpl ? "NotImpl" : \
- (X) == kDNSFlag1_RC_Refused ? "Refused" : \
- (X) == kDNSFlag1_RC_YXDomain ? "YXDomain" : \
- (X) == kDNSFlag1_RC_YXRRSet ? "YXRRSet" : \
- (X) == kDNSFlag1_RC_NXRRSet ? "NXRRSet" : \
- (X) == kDNSFlag1_RC_NotAuth ? "NotAuth" : \
- (X) == kDNSFlag1_RC_NotZone ? "NotZone" : "??" )
-
-mDNSlocal void mDNS_snprintf_add(char **ptr, const char *lim, const char *fmt, ...)
+ (X) == kDNSFlag1_RC_NoErr ? "NoErr" : \
+ (X) == kDNSFlag1_RC_FormErr ? "FormErr" : \
+ (X) == kDNSFlag1_RC_ServFail ? "ServFail" : \
+ (X) == kDNSFlag1_RC_NXDomain ? "NXDomain" : \
+ (X) == kDNSFlag1_RC_NotImpl ? "NotImpl" : \
+ (X) == kDNSFlag1_RC_Refused ? "Refused" : \
+ (X) == kDNSFlag1_RC_YXDomain ? "YXDomain" : \
+ (X) == kDNSFlag1_RC_YXRRSet ? "YXRRSet" : \
+ (X) == kDNSFlag1_RC_NXRRSet ? "NXRRSet" : \
+ (X) == kDNSFlag1_RC_NotAuth ? "NotAuth" : \
+ (X) == kDNSFlag1_RC_NotZone ? "NotZone" : \
+ (X) == kDNSFlag1_RC_DSOTypeNI ? "DSOTypeNI" : "??" )
+
+mDNSexport void mDNS_snprintf_add(char **ptr, const char *lim, const char *fmt, ...)
{
va_list args;
mDNSu32 buflen, n;
@@ -3678,34 +3411,17 @@ mDNSlocal void mDNS_snprintf_add(char **ptr, const char *lim, const char *fmt, .
(((mDNSu32)((mDNSu8 *)(PTR))[2]) << 8) | \
((mDNSu32)((mDNSu8 *)(PTR))[3])))
-mDNSlocal void DNSMessageDump(const DNSMessage *const msg, const mDNSu8 *const end, char *buffer, mDNSu32 buflen)
+mDNSlocal void DNSMessageDumpToLog(const DNSMessage *const msg, const mDNSu8 *const end)
{
- domainname *name;
- const mDNSu8 *ptr;
+ domainname *name = mDNSNULL;
+ const mDNSu8 *ptr = msg->data;
domainname nameStorage[2];
- char *dst = buffer;
- const char *const lim = &buffer[buflen];
- mDNSu32 i;
- const mDNSu32 rrcount = msg->h.numAnswers + msg->h.numAuthorities + msg->h.numAdditionals;
- mDNS_snprintf_add(&dst, lim, "DNS %s%s (%lu) (flags %02X%02X) RCODE: %s (%d)%s%s%s%s%s%s ID: %u:",
- DNS_OP_Name(msg->h.flags.b[0] & kDNSFlag0_OP_Mask),
- (msg->h.flags.b[0] & kDNSFlag0_QR_Response) ? "Response" : "Query",
- (unsigned long)(end - (const mDNSu8 *)msg),
- msg->h.flags.b[0], msg->h.flags.b[1],
- DNS_RC_Name(msg->h.flags.b[1] & kDNSFlag1_RC_Mask),
- msg->h.flags.b[1] & kDNSFlag1_RC_Mask,
- (msg->h.flags.b[0] & kDNSFlag0_AA) ? " AA" : "",
- (msg->h.flags.b[0] & kDNSFlag0_TC) ? " TC" : "",
- (msg->h.flags.b[0] & kDNSFlag0_RD) ? " RD" : "",
- (msg->h.flags.b[1] & kDNSFlag1_RA) ? " RA" : "",
- (msg->h.flags.b[1] & kDNSFlag1_AD) ? " AD" : "",
- (msg->h.flags.b[1] & kDNSFlag1_CD) ? " CD" : "",
- mDNSVal16(msg->h.id));
-
- name = mDNSNULL;
- ptr = msg->data;
- for (i = 0; i < msg->h.numQuestions; i++)
+ char questions[512];
+ questions[0] = '\0';
+ char *questions_dst = questions;
+ const char *const questions_lim = &questions[512];
+ for (mDNSu32 i = 0; i < msg->h.numQuestions; i++)
{
mDNSu16 qtype, qclass;
@@ -3718,13 +3434,17 @@ mDNSlocal void DNSMessageDump(const DNSMessage *const msg, const mDNSu8 *const e
qclass = ReadField16(&ptr[2]);
ptr += 4;
- mDNS_snprintf_add(&dst, lim, " %##s %s", name->c, DNSTypeString(qtype));
- if (qclass != kDNSClass_IN) mDNS_snprintf_add(&dst, lim, "/%u", qclass);
- mDNS_snprintf_add(&dst, lim, "?");
+ mDNS_snprintf_add(&questions_dst, questions_lim, " %##s %s", name->c, DNSTypeString(qtype));
+ if (qclass != kDNSClass_IN) mDNS_snprintf_add(&questions_dst, questions_lim, "/%u", qclass);
+ mDNS_snprintf_add(&questions_dst, questions_lim, "?");
}
- mDNS_snprintf_add(&dst, lim, " %u/%u/%u", msg->h.numAnswers, msg->h.numAuthorities, msg->h.numAdditionals);
- for (i = 0; i < rrcount; i++)
+ char rrs[512];
+ rrs[0] = '\0';
+ char *rrs_dst = rrs;
+ const char *const rrs_lim = &rrs[512];
+ const mDNSu32 rrcount = msg->h.numAnswers + msg->h.numAuthorities + msg->h.numAdditionals;
+ for (mDNSu32 i = 0; i < rrcount; i++)
{
mDNSu16 rrtype, rrclass, rdlength;
mDNSu32 ttl;
@@ -3746,104 +3466,119 @@ mDNSlocal void DNSMessageDump(const DNSMessage *const msg, const mDNSu8 *const e
if ((end - ptr) < rdlength) goto exit;
rdata = ptr;
- if (i > 0) mDNS_snprintf_add(&dst, lim, ",");
- if (!previousName || !SameDomainName(name, previousName)) mDNS_snprintf_add(&dst, lim, " %##s", name);
+ if (i > 0) mDNS_snprintf_add(&rrs_dst, rrs_lim, ",");
+ if (!previousName || !SameDomainName(name, previousName)) mDNS_snprintf_add(&rrs_dst, rrs_lim, " %##s", name);
- mDNS_snprintf_add(&dst, lim, " %s", DNSTypeString(rrtype));
- if (rrclass != kDNSClass_IN) mDNS_snprintf_add(&dst, lim, "/%u", rrclass);
- mDNS_snprintf_add(&dst, lim, " ");
+ mDNS_snprintf_add(&rrs_dst, rrs_lim, " %s", DNSTypeString(rrtype));
+ if (rrclass != kDNSClass_IN) mDNS_snprintf_add(&rrs_dst, rrs_lim, "/%u", rrclass);
+ mDNS_snprintf_add(&rrs_dst, rrs_lim, " ");
handled = mDNSfalse;
switch (rrtype)
{
- case kDNSType_A:
- if (rdlength == 4)
- {
- mDNS_snprintf_add(&dst, lim, "%.4a", rdata);
- handled = mDNStrue;
- }
- break;
+ case kDNSType_A:
+ if (rdlength == 4)
+ {
+ mDNS_snprintf_add(&rrs_dst, rrs_lim, "%.4a", rdata);
+ handled = mDNStrue;
+ }
+ break;
- case kDNSType_AAAA:
- if (rdlength == 16)
- {
- mDNS_snprintf_add(&dst, lim, "%.16a", rdata);
- handled = mDNStrue;
- }
- break;
+ case kDNSType_AAAA:
+ if (rdlength == 16)
+ {
+ mDNS_snprintf_add(&rrs_dst, rrs_lim, "%.16a", rdata);
+ handled = mDNStrue;
+ }
+ break;
- case kDNSType_CNAME:
- ptr = getDomainName(msg, rdata, end, name);
- if (!ptr) goto exit;
+ case kDNSType_CNAME:
+ ptr = getDomainName(msg, rdata, end, name);
+ if (!ptr) goto exit;
- mDNS_snprintf_add(&dst, lim, "%##s", name);
- handled = mDNStrue;
- break;
+ mDNS_snprintf_add(&rrs_dst, rrs_lim, "%##s", name);
+ handled = mDNStrue;
+ break;
- case kDNSType_SOA:
- {
- mDNSu32 serial, refresh, retry, expire, minimum;
- domainname *const mname = &nameStorage[0];
- domainname *const rname = &nameStorage[1];
- name = mDNSNULL;
+ case kDNSType_SOA:
+ {
+ mDNSu32 serial, refresh, retry, expire, minimum;
+ domainname *const mname = &nameStorage[0];
+ domainname *const rname = &nameStorage[1];
+ name = mDNSNULL;
- ptr = getDomainName(msg, rdata, end, mname);
- if (!ptr) goto exit;
+ ptr = getDomainName(msg, rdata, end, mname);
+ if (!ptr) goto exit;
- ptr = getDomainName(msg, ptr, end, rname);
- if (!ptr) goto exit;
+ ptr = getDomainName(msg, ptr, end, rname);
+ if (!ptr) goto exit;
- if ((end - ptr) < 20) goto exit;
- serial = ReadField32(&ptr[0]);
- refresh = ReadField32(&ptr[4]);
- retry = ReadField32(&ptr[8]);
- expire = ReadField32(&ptr[12]);
- minimum = ReadField32(&ptr[16]);
+ if ((end - ptr) < 20) goto exit;
+ serial = ReadField32(&ptr[0]);
+ refresh = ReadField32(&ptr[4]);
+ retry = ReadField32(&ptr[8]);
+ expire = ReadField32(&ptr[12]);
+ minimum = ReadField32(&ptr[16]);
- mDNS_snprintf_add(&dst, lim, "%##s %##s %lu %lu %lu %lu %lu", mname, rname, (unsigned long)serial,
- (unsigned long)refresh, (unsigned long)retry, (unsigned long)expire, (unsigned long)minimum);
+ mDNS_snprintf_add(&rrs_dst, rrs_lim, "%##s %##s %lu %lu %lu %lu %lu", mname, rname, (unsigned long)serial,
+ (unsigned long)refresh, (unsigned long)retry, (unsigned long)expire, (unsigned long)minimum);
- handled = mDNStrue;
- break;
- }
+ handled = mDNStrue;
+ break;
+ }
- default:
- break;
+ default:
+ break;
}
- if (!handled) mDNS_snprintf_add(&dst, lim, "RDATA[%u]: %.*H", rdlength, rdlength, rdata);
- mDNS_snprintf_add(&dst, lim, " (%lu)", (unsigned long)ttl);
+ if (!handled) mDNS_snprintf_add(&rrs_dst, rrs_lim, "RDATA[%u]: %.*H", rdlength, rdlength, rdata);
+ mDNS_snprintf_add(&rrs_dst, rrs_lim, " (%lu)", (unsigned long)ttl);
ptr = rdata + rdlength;
}
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[Q%u] DNS " PUB_S PUB_S " (%lu) (flags %02X%02X) RCODE: " PUB_S " (%d)" PUB_S PUB_S PUB_S PUB_S PUB_S PUB_S ":"
+ PRI_S " %u/%u/%u " PRI_S,
+ mDNSVal16(msg->h.id),
+ DNS_OP_Name(msg->h.flags.b[0] & kDNSFlag0_OP_Mask),
+ (msg->h.flags.b[0] & kDNSFlag0_QR_Response) ? "Response" : "Query",
+ (unsigned long)(end - (const mDNSu8 *)msg),
+ msg->h.flags.b[0], msg->h.flags.b[1],
+ DNS_RC_Name(msg->h.flags.b[1] & kDNSFlag1_RC_Mask),
+ msg->h.flags.b[1] & kDNSFlag1_RC_Mask,
+ (msg->h.flags.b[0] & kDNSFlag0_AA) ? " AA" : "",
+ (msg->h.flags.b[0] & kDNSFlag0_TC) ? " TC" : "",
+ (msg->h.flags.b[0] & kDNSFlag0_RD) ? " RD" : "",
+ (msg->h.flags.b[1] & kDNSFlag1_RA) ? " RA" : "",
+ (msg->h.flags.b[1] & kDNSFlag1_AD) ? " AD" : "",
+ (msg->h.flags.b[1] & kDNSFlag1_CD) ? " CD" : "",
+ questions, msg->h.numAnswers, msg->h.numAuthorities, msg->h.numAdditionals, rrs);
+
exit:
return;
}
// Note: DumpPacket expects the packet header fields in host byte order, not network byte order
-mDNSexport void DumpPacket(mStatus status, mDNSBool sent, char *transport,
- const mDNSAddr *srcaddr, mDNSIPPort srcport,
- const mDNSAddr *dstaddr, mDNSIPPort dstport, const DNSMessage *const msg, const mDNSu8 *const end)
+mDNSexport void DumpPacket(mStatus status, mDNSBool sent, const char *transport,
+ const mDNSAddr *srcaddr, mDNSIPPort srcport,const mDNSAddr *dstaddr, mDNSIPPort dstport, const DNSMessage *const msg,
+ const mDNSu8 *const end, mDNSInterfaceID interfaceID)
{
- char buffer[512];
- char *dst = buffer;
- const char *const lim = &buffer[512];
+ const mDNSAddr zeroIPv4Addr = { mDNSAddrType_IPv4, {{{ 0 }}} };
+ char action[32];
+ const char* interfaceName = "interface";
- buffer[0] = '\0';
- if (!status) mDNS_snprintf_add(&dst, lim, sent ? "Sent" : "Received");
- else mDNS_snprintf_add(&dst, lim, "ERROR %d %sing", status, sent ? "Send" : "Receiv");
+ if (!status) mDNS_snprintf(action, sizeof(action), sent ? "Sent" : "Received");
+ else mDNS_snprintf(action, sizeof(action), "ERROR %d %sing", status, sent ? "Send" : "Receiv");
- mDNS_snprintf_add(&dst, lim, " %s DNS Message %u bytes from ", transport, (unsigned long)(end - (const mDNSu8 *)msg));
-
- if (sent) mDNS_snprintf_add(&dst, lim, "port %d", mDNSVal16(srcport));
- else mDNS_snprintf_add(&dst, lim, "%#a:%d", srcaddr, mDNSVal16(srcport));
-
- if (dstaddr || !mDNSIPPortIsZero(dstport)) mDNS_snprintf_add(&dst, lim, " to %#a:%d", dstaddr, mDNSVal16(dstport));
-
- LogInfo("%s", buffer);
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+ interfaceName = InterfaceNameForID(&mDNSStorage, interfaceID);
+#endif
- buffer[0] = '\0';
- DNSMessageDump(msg, end, buffer, (mDNSu32)sizeof(buffer));
- LogInfo("%s", buffer);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[Q%u] " PUB_S " " PUB_S " DNS Message %lu bytes from " PRI_IP_ADDR ":%d to " PRI_IP_ADDR ":%d via " PUB_S " (%p)",
+ mDNSVal16(msg->h.id), action, transport, (unsigned long)(end - (const mDNSu8 *)msg),
+ srcaddr ? srcaddr : &zeroIPv4Addr, mDNSVal16(srcport), dstaddr ? dstaddr : &zeroIPv4Addr, mDNSVal16(dstport),
+ interfaceName, interfaceID);
+ DNSMessageDumpToLog(msg, end);
}
// ***************************************************************************
@@ -3852,26 +3587,19 @@ mDNSexport void DumpPacket(mStatus status, mDNSBool sent, char *transport,
#pragma mark - Packet Sending Functions
#endif
-#ifdef UNIT_TEST
-// Run the unit test of mDNSSendDNSMessage
-UNITTEST_SENDDNSMESSAGE
-#else
// Stub definition of TCPSocket_struct so we can access flags field. (Rest of TCPSocket_struct is platform-dependent.)
-struct TCPSocket_struct { TCPSocketFlags flags; /* ... */ };
+struct TCPSocket_struct { mDNSIPPort port; TCPSocketFlags flags; /* ... */ };
// Stub definition of UDPSocket_struct so we can access port field. (Rest of UDPSocket_struct is platform-dependent.)
struct UDPSocket_struct { mDNSIPPort port; /* ... */ };
// Note: When we sign a DNS message using DNSDigest_SignMessage(), the current real-time clock value is used, which
// is why we generally defer signing until we send the message, to ensure the signature is as fresh as possible.
mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNSu8 *end,
- mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst,
- mDNSIPPort dstport, TCPSocket *sock, DomainAuthInfo *authInfo,
- mDNSBool useBackgroundTrafficClass)
+ mDNSInterfaceID InterfaceID, TCPSocket *tcpSrc, UDPSocket *udpSrc, const mDNSAddr *dst,
+ mDNSIPPort dstport, DomainAuthInfo *authInfo, mDNSBool useBackgroundTrafficClass)
{
mStatus status = mStatus_NoError;
const mDNSu16 numAdditionals = msg->h.numAdditionals;
- mDNSu8 *newend;
- mDNSu8 *limit = msg->data + AbsoluteMaxDNSMessageData;
#if APPLE_OSX_mDNSResponder
// maintain outbound packet statistics
@@ -3888,10 +3616,6 @@ mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNS
return mStatus_BadParamErr;
}
- newend = putHINFO(m, msg, end, authInfo, limit);
- if (!newend) LogMsg("mDNSSendDNSMessage: putHINFO failed msg %p end %p, limit %p", msg->data, end, limit); // Not fatal
- else end = newend;
-
// Put all the integer values in IETF byte-order (MSB first, LSB second)
SwapDNSHeaderBytes(msg);
@@ -3900,8 +3624,8 @@ mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNS
else
{
// Send the packet on the wire
- if (!sock)
- status = mDNSPlatformSendUDP(m, msg, end, InterfaceID, src, dst, dstport, useBackgroundTrafficClass);
+ if (!tcpSrc)
+ status = mDNSPlatformSendUDP(m, msg, end, InterfaceID, udpSrc, dst, dstport, useBackgroundTrafficClass);
else
{
mDNSu16 msglen = (mDNSu16)(end - (mDNSu8 *)msg);
@@ -3910,13 +3634,13 @@ mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNS
long nsent;
// Try to send them in one packet if we can allocate enough memory
- buf = mDNSPlatformMemAllocate(msglen + 2);
+ buf = (char *) mDNSPlatformMemAllocate(msglen + 2);
if (buf)
{
buf[0] = lenbuf[0];
buf[1] = lenbuf[1];
mDNSPlatformMemCopy(buf+2, msg, msglen);
- nsent = mDNSPlatformWriteTCP(sock, buf, msglen+2);
+ nsent = mDNSPlatformWriteTCP(tcpSrc, buf, msglen+2);
if (nsent != (msglen + 2))
{
LogMsg("mDNSSendDNSMessage: write message failed %d/%d", nsent, msglen);
@@ -3926,7 +3650,7 @@ mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNS
}
else
{
- nsent = mDNSPlatformWriteTCP(sock, (char*)lenbuf, 2);
+ nsent = mDNSPlatformWriteTCP(tcpSrc, (char*)lenbuf, 2);
if (nsent != 2)
{
LogMsg("mDNSSendDNSMessage: write msg length failed %d/%d", nsent, 2);
@@ -3934,7 +3658,7 @@ mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNS
}
else
{
- nsent = mDNSPlatformWriteTCP(sock, (char *)msg, msglen);
+ nsent = mDNSPlatformWriteTCP(tcpSrc, (char *)msg, msglen);
if (nsent != msglen)
{
LogMsg("mDNSSendDNSMessage: write msg body failed %d/%d", nsent, msglen);
@@ -3950,14 +3674,25 @@ mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNS
// Dump the packet with the HINFO and TSIG
if (mDNS_PacketLoggingEnabled && !mDNSOpaque16IsZero(msg->h.id))
- DumpPacket(status, mDNStrue, sock && (sock->flags & kTCPSocketFlags_UseTLS) ? "TLS" : sock ? "TCP" : "UDP", mDNSNULL, src ? src->port : MulticastDNSPort, dst, dstport, msg, end);
+ {
+ char *transport = "UDP";
+ mDNSIPPort portNumber = udpSrc ? udpSrc->port : MulticastDNSPort;
+ if (tcpSrc)
+ {
+ if (tcpSrc->flags)
+ transport = "TLS";
+ else
+ transport = "TCP";
+ portNumber = tcpSrc->port;
+ }
+ DumpPacket(status, mDNStrue, transport, mDNSNULL, portNumber, dst, dstport, msg, end, InterfaceID);
+ }
// put the number of additionals back the way it was
msg->h.numAdditionals = numAdditionals;
return(status);
}
-#endif // UNIT_TEST
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
@@ -4038,9 +3773,9 @@ mDNSlocal mDNSs32 GetNextScheduledEvent(const mDNS *const m)
if (e - m->NextScheduledSPS > 0) e = m->NextScheduledSPS;
if (e - m->NextScheduledKA > 0) e = m->NextScheduledKA;
-#if BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
if (m->NextBonjourDisableTime && (e - m->NextBonjourDisableTime > 0)) e = m->NextBonjourDisableTime;
-#endif // BONJOUR_ON_DEMAND
+#endif
// NextScheduledSPRetry only valid when DelaySleep not set
if (!m->DelaySleep && m->SleepLimit && e - m->NextScheduledSPRetry > 0) e = m->NextScheduledSPRetry;
@@ -4486,7 +4221,7 @@ hexadecimal: if (F.lSize) n = va_arg(arg, unsigned long);
default: s = mDNS_VACB;
i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "<<UNKNOWN FORMAT CONVERSION CODE %%%c>>", c);
- /* FALLTHROUGH */
+ break;
case '%': *sbuffer++ = (char)c;
if (++nwritten >= buflen) goto exit;
@@ -4553,3 +4288,53 @@ mDNSexport mDNSu32 mDNS_snprintf(char *sbuffer, mDNSu32 buflen, const char *fmt,
return(length);
}
+
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+mDNSexport mDNSu32 mDNS_GetNextResolverGroupID(void)
+{
+ static mDNSu32 lastID = 0;
+ if (++lastID == 0) lastID = 1; // Valid resolver group IDs are non-zero.
+ return(lastID);
+}
+#endif
+
+#define kReverseIPv6Domain ((const domainname *) "\x3" "ip6" "\x4" "arpa")
+
+mDNSexport mDNSBool GetReverseIPv6Addr(const domainname *name, mDNSu8 outIPv6[16])
+{
+ const mDNSu8 * ptr;
+ int i;
+ mDNSu8 ipv6[16];
+
+ // If the name is of the form "x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.ip6.arpa.", where each x
+ // is a hex digit, then the sequence of 32 hex digit labels represents the nibbles of an IPv6 address in reverse order.
+ // See <https://tools.ietf.org/html/rfc3596#section-2.5>.
+
+ ptr = name->c;
+ for (i = 0; i < 32; i++)
+ {
+ unsigned int c, nibble;
+ const int j = 15 - (i / 2);
+ if (*ptr++ != 1) return (mDNSfalse); // If this label's length is not 1, then fail.
+ c = *ptr++; // Get label byte.
+ if ( (c >= '0') && (c <= '9')) nibble = c - '0'; // If it's a hex digit, get its numeric value.
+ else if ((c >= 'a') && (c <= 'f')) nibble = (c - 'a') + 10;
+ else if ((c >= 'A') && (c <= 'F')) nibble = (c - 'A') + 10;
+ else return (mDNSfalse); // Otherwise, fail.
+ if ((i % 2) == 0)
+ {
+ ipv6[j] = (mDNSu8)nibble;
+ }
+ else
+ {
+ ipv6[j] |= (mDNSu8)(nibble << 4);
+ }
+ }
+
+ // The rest of the name needs to be "ip6.arpa.". If it isn't, fail.
+
+ if (!SameDomainName((const domainname *)ptr, kReverseIPv6Domain)) return (mDNSfalse);
+ if (outIPv6) mDNSPlatformMemCopy(outIPv6, ipv6, 16);
+ return (mDNStrue);
+}
+#endif // !STANDALONE
diff --git a/usr/src/contrib/mDNSResponder/mDNSCore/DNSCommon.h b/usr/src/contrib/mDNSResponder/mDNSCore/DNSCommon.h
index 6e468cdb81..48de85f609 100644
--- a/usr/src/contrib/mDNSResponder/mDNSCore/DNSCommon.h
+++ b/usr/src/contrib/mDNSResponder/mDNSCore/DNSCommon.h
@@ -1,6 +1,6 @@
/* -*- Mode: C; tab-width: 4 -*-
*
- * Copyright (c) 2002-2018 Apple Inc. All rights reserved.
+ * Copyright (c) 2002-2020 Apple Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -44,15 +44,14 @@ typedef enum
kDNSFlag0_QR_Query = 0x00,
kDNSFlag0_QR_Response = 0x80,
- kDNSFlag0_OP_Mask = 0x78, // Operation type
- kDNSFlag0_OP_StdQuery = 0x00,
- kDNSFlag0_OP_Subscribe = 0x06,
- kDNSFlag0_OP_UnSubscribe = 0x07,
- kDNSFlag0_OP_Iquery = 0x08,
- kDNSFlag0_OP_Status = 0x10,
- kDNSFlag0_OP_Unused3 = 0x18,
- kDNSFlag0_OP_Notify = 0x20,
- kDNSFlag0_OP_Update = 0x28,
+ kDNSFlag0_OP_Mask = 0xF << 3, // Operation type
+ kDNSFlag0_OP_StdQuery = 0x0 << 3,
+ kDNSFlag0_OP_Iquery = 0x1 << 3,
+ kDNSFlag0_OP_Status = 0x2 << 3,
+ kDNSFlag0_OP_Unused3 = 0x3 << 3,
+ kDNSFlag0_OP_Notify = 0x4 << 3,
+ kDNSFlag0_OP_Update = 0x5 << 3,
+ kDNSFlag0_OP_DSO = 0x6 << 3,
kDNSFlag0_QROP_Mask = kDNSFlag0_QR_Mask | kDNSFlag0_OP_Mask,
@@ -76,7 +75,8 @@ typedef enum
kDNSFlag1_RC_YXRRSet = 0x07,
kDNSFlag1_RC_NXRRSet = 0x08,
kDNSFlag1_RC_NotAuth = 0x09,
- kDNSFlag1_RC_NotZone = 0x0A
+ kDNSFlag1_RC_NotZone = 0x0A,
+ kDNSFlag1_RC_DSOTypeNI = 0x0B
} DNS_Flags;
typedef enum
@@ -98,6 +98,10 @@ extern mDNSInterfaceID GetNextActiveInterfaceID(const NetworkInterfaceInfo *intf
extern mDNSu32 mDNSRandom(mDNSu32 max); // Returns pseudo-random result from zero to max inclusive
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+extern mDNSu32 mDNS_GetNextResolverGroupID(void);
+#endif
+
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
@@ -116,7 +120,8 @@ extern mDNSu32 mDNSRandom(mDNSu32 max); // Returns pseudo-random result from
// We set the maximum allowable TTL to one hour.
// With the 25% correction factor to avoid the DNS Zeno's paradox bug, that gives us an actual maximum lifetime of 75 minutes.
-#define mDNSMaximumTTLSeconds (mDNSu32)3600
+#define mDNSMaximumMulticastTTLSeconds (mDNSu32)4500
+#define mDNSMaximumUnicastTTLSeconds (mDNSu32)3600
#define mDNSValidHostChar(X, notfirst, notlast) (mDNSIsLetter(X) || mDNSIsDigit(X) || ((notfirst) && (notlast) && (X) == '-') )
@@ -174,9 +179,11 @@ extern void AppendLabelSuffix(domainlabel *const name, mDNSu32 val, const mDNSBo
extern mDNSu32 RDataHashValue(const ResourceRecord *const rr);
extern mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *const r2, DomainNameComparisonFn *samename);
-extern mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
+extern mDNSBool SameNameCacheRecordAnswersQuestion(const CacheRecord *const cr, const DNSQuestion *const q);
extern mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
-extern mDNSBool AnyTypeRecordAnswersQuestion (const ResourceRecord *const rr, const DNSQuestion *const q);
+extern mDNSBool AuthRecordAnswersQuestion(const AuthRecord *const ar, const DNSQuestion *const q);
+extern mDNSBool CacheRecordAnswersQuestion(const CacheRecord *const cr, const DNSQuestion *const q);
+extern mDNSBool AnyTypeRecordAnswersQuestion (const AuthRecord *const ar, const DNSQuestion *const q);
extern mDNSBool ResourceRecordAnswersUnicastResponse(const ResourceRecord *const rr, const DNSQuestion *const q);
extern mDNSBool LocalOnlyRecordAnswersQuestion(AuthRecord *const rr, const DNSQuestion *const q);
extern mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate);
@@ -206,7 +213,8 @@ extern mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *
#define AllowedRRSpace(msg) (((msg)->h.numAnswers || (msg)->h.numAuthorities || (msg)->h.numAdditionals) ? NormalMaxDNSMessageData : AbsoluteMaxDNSMessageData)
-extern mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, ResourceRecord *rr, mDNSu32 ttl, const mDNSu8 *limit);
+extern mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, const ResourceRecord *rr,
+ mDNSu32 ttl, const mDNSu8 *limit);
#define PutResourceRecordTTL(msg, ptr, count, rr, ttl) \
PutResourceRecordTTLWithLimit((msg), (ptr), (count), (rr), (ttl), (msg)->data + AllowedRRSpace(msg))
@@ -233,14 +241,9 @@ extern mDNSu8 *putDeleteAllRRSets(DNSMessage *msg, mDNSu8 *ptr, const domainname
extern mDNSu8 *putUpdateLease(DNSMessage *msg, mDNSu8 *ptr, mDNSu32 lease);
extern mDNSu8 *putUpdateLeaseWithLimit(DNSMessage *msg, mDNSu8 *ptr, mDNSu32 lease, mDNSu8 *limit);
-extern mDNSu8 *putHINFO(const mDNS *const m, DNSMessage *const msg, mDNSu8 *ptr, DomainAuthInfo *authInfo, mDNSu8 *limit);
-extern mDNSu8 *putDNSSECOption(DNSMessage *msg, mDNSu8 *end, mDNSu8 *limit);
extern int baseEncode(char *buffer, int blen, const mDNSu8 *data, int len, int encAlg);
extern void NSEC3Parse(const ResourceRecord *const rr, mDNSu8 **salt, int *hashLength, mDNSu8 **nxtName, int *bitmaplen, mDNSu8 **bitmap);
-extern const mDNSu8 *NSEC3HashName(const domainname *name, rdataNSEC3 *nsec3, const mDNSu8 *AnonData, int AnonDataLen,
- const mDNSu8 hash[NSEC3_MAX_HASH_LEN], int *dlen);
-
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
@@ -256,8 +259,8 @@ extern const mDNSu8 *getDomainName(const DNSMessage *const msg, const mDNSu8 *pt
extern const mDNSu8 *skipResourceRecord(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end);
extern const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage * const msg, const mDNSu8 *ptr,
const mDNSu8 * end, const mDNSInterfaceID InterfaceID, mDNSu8 RecordType, LargeCacheRecord *const largecr);
-extern mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *end,
- LargeCacheRecord *const largecr, mDNSu16 rdlength);
+extern mDNSBool SetRData(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *end, ResourceRecord *rr,
+ mDNSu16 rdlength);
extern const mDNSu8 *skipQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end);
extern const mDNSu8 *getQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end, const mDNSInterfaceID InterfaceID,
DNSQuestion *question);
@@ -267,9 +270,9 @@ extern const mDNSu8 *LocateAdditionals(const DNSMessage *const msg, const mDNSu8
extern const mDNSu8 *LocateOptRR(const DNSMessage *const msg, const mDNSu8 *const end, int minsize);
extern const rdataOPT *GetLLQOptData(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end);
extern mDNSBool GetPktLease(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, mDNSu32 *const lease);
-extern void DumpPacket(mStatus status, mDNSBool sent, char *transport,
- const mDNSAddr *srcaddr, mDNSIPPort srcport,
- const mDNSAddr *dstaddr, mDNSIPPort dstport, const DNSMessage *const msg, const mDNSu8 *const end);
+extern void DumpPacket(mStatus status, mDNSBool sent, const char *transport, const mDNSAddr *srcaddr, mDNSIPPort srcport,
+ const mDNSAddr *dstaddr, mDNSIPPort dstport, const DNSMessage *const msg, const mDNSu8 *const end,
+ mDNSInterfaceID interfaceID);
extern mDNSBool RRAssertsNonexistence(const ResourceRecord *const rr, mDNSu16 type);
extern mDNSBool RRAssertsExistence(const ResourceRecord *const rr, mDNSu16 type);
extern mDNSBool BitmapTypeCheck(mDNSu8 *bmap, int bitmaplen, mDNSu16 type);
@@ -277,16 +280,16 @@ extern mDNSBool BitmapTypeCheck(mDNSu8 *bmap, int bitmaplen, mDNSu16 type);
extern mDNSu16 swap16(mDNSu16 x);
extern mDNSu32 swap32(mDNSu32 x);
+extern mDNSBool GetReverseIPv6Addr(const domainname *inQName, mDNSu8 outIPv6[16]);
+
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
#pragma mark - Packet Sending Functions
#endif
-
extern mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNSu8 *end,
- mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst,
- mDNSIPPort dstport, TCPSocket *sock, DomainAuthInfo *authInfo,
- mDNSBool useBackgroundTrafficClass);
+ mDNSInterfaceID InterfaceID, TCPSocket *tcpSrc, UDPSocket *udpSrc, const mDNSAddr *dst,
+ mDNSIPPort dstport, DomainAuthInfo *authInfo, mDNSBool useBackgroundTrafficClass);
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
@@ -297,7 +300,7 @@ extern mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNSu8 *
extern void ShowTaskSchedulingError(mDNS *const m);
extern void mDNS_Lock_(mDNS *const m, const char * const functionname);
extern void mDNS_Unlock_(mDNS *const m, const char * const functionname);
-
+
#if defined(_WIN32)
#define __func__ __FUNCTION__
#endif
diff --git a/usr/src/contrib/mDNSResponder/mDNSCore/DNSDigest.c b/usr/src/contrib/mDNSResponder/mDNSCore/DNSDigest.c
index 6520ac6f6e..5b1c228957 100644
--- a/usr/src/contrib/mDNSResponder/mDNSCore/DNSDigest.c
+++ b/usr/src/contrib/mDNSResponder/mDNSCore/DNSDigest.c
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2011 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2002-2019 Apple Inc. All rights reserved.
* Copyright (c) 2016 by Delphix. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -571,27 +570,34 @@ void md5_block_data_order (MD5_CTX *c, const void *p,int num);
l|=(((unsigned long)(*((c)++)))<< 8), \
l|=(((unsigned long)(*((c)++))) ), \
l)
-#define HOST_p_c2l(c,l,n) { \
- switch (n) { \
+#define HOST_p_c2l(c,l,n) { \
+ switch (n) { \
case 0: l =((unsigned long)(*((c)++)))<<24; \
+ /* FALLTHROUGH */ \
case 1: l|=((unsigned long)(*((c)++)))<<16; \
+ /* FALLTHROUGH */ \
case 2: l|=((unsigned long)(*((c)++)))<< 8; \
+ /* FALLTHROUGH */ \
case 3: l|=((unsigned long)(*((c)++))); \
} }
#define HOST_p_c2l_p(c,l,sc,len) { \
- switch (sc) { \
+ switch (sc) { \
case 0: l =((unsigned long)(*((c)++)))<<24; \
- if (--len == 0) break; \
+ if (--len == 0) break; \
+ /* FALLTHROUGH */ \
case 1: l|=((unsigned long)(*((c)++)))<<16; \
- if (--len == 0) break; \
+ if (--len == 0) break; \
+ /* FALLTHROUGH */ \
case 2: l|=((unsigned long)(*((c)++)))<< 8; \
} }
/* NOTE the pointer is not incremented at the end of this */
-#define HOST_c2l_p(c,l,n) { \
- l=0; (c)+=n; \
- switch (n) { \
+#define HOST_c2l_p(c,l,n) { \
+ l=0; (c)+=n; \
+ switch (n) { \
case 3: l =((unsigned long)(*(--(c))))<< 8; \
+ /* FALLTHROUGH */ \
case 2: l|=((unsigned long)(*(--(c))))<<16; \
+ /* FALLTHROUGH */ \
case 1: l|=((unsigned long)(*(--(c))))<<24; \
} }
#define _HOST_l2c(l,c) (*((c)++)=(unsigned char)(((l)>>24)&0xff), \
@@ -607,34 +613,34 @@ void md5_block_data_order (MD5_CTX *c, const void *p,int num);
l|=(((unsigned long)(*((c)++)))<<16), \
l|=(((unsigned long)(*((c)++)))<<24), \
l)
-#define HOST_p_c2l(c,l,n) { \
- switch (n) { \
+#define HOST_p_c2l(c,l,n) { \
+ switch (n) { \
case 0: l =((unsigned long)(*((c)++))); \
- /* FALLTHROUGH */ \
+ /* FALLTHROUGH */ \
case 1: l|=((unsigned long)(*((c)++)))<< 8; \
- /* FALLTHROUGH */ \
+ /* FALLTHROUGH */ \
case 2: l|=((unsigned long)(*((c)++)))<<16; \
- /* FALLTHROUGH */ \
+ /* FALLTHROUGH */ \
case 3: l|=((unsigned long)(*((c)++)))<<24; \
} }
#define HOST_p_c2l_p(c,l,sc,len) { \
- switch (sc) { \
+ switch (sc) { \
case 0: l =((unsigned long)(*((c)++))); \
- if (--len == 0) break; \
- /* FALLTHROUGH */ \
+ if (--len == 0) break; \
+ /* FALLTHROUGH */ \
case 1: l|=((unsigned long)(*((c)++)))<< 8; \
- if (--len == 0) break; \
- /* FALLTHROUGH */ \
+ if (--len == 0) break; \
+ /* FALLTHROUGH */ \
case 2: l|=((unsigned long)(*((c)++)))<<16; \
} }
/* NOTE the pointer is not incremented at the end of this */
-#define HOST_c2l_p(c,l,n) { \
- l=0; (c)+=n; \
- switch (n) { \
+#define HOST_c2l_p(c,l,n) { \
+ l=0; (c)+=n; \
+ switch (n) { \
case 3: l =((unsigned long)(*(--(c))))<<16; \
- /* FALLTHROUGH */ \
+ /* FALLTHROUGH */ \
case 2: l|=((unsigned long)(*(--(c))))<< 8; \
- /* FALLTHROUGH */ \
+ /* FALLTHROUGH */ \
case 1: l|=((unsigned long)(*(--(c)))); \
} }
#define _HOST_l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \
@@ -652,6 +658,7 @@ void md5_block_data_order (MD5_CTX *c, const void *p,int num);
int HASH_UPDATE (HASH_CTX *c, const void *data_, unsigned long len)
{
const unsigned char *data=(const unsigned char *)data_;
+ const unsigned char * const data_end=(const unsigned char *)data_;
register HASH_LONG * p;
register unsigned long l;
int sw,sc,ew,ec;
@@ -675,7 +682,7 @@ int HASH_UPDATE (HASH_CTX *c, const void *data_, unsigned long len)
if ((c->num+len) >= HASH_CBLOCK)
{
l=p[sw]; HOST_p_c2l(data,l,sc); p[sw++]=l;
- for (; sw<HASH_LBLOCK; sw++)
+ for (; (sw < HASH_LBLOCK) && ((data_end - data) >= 4); sw++)
{
HOST_c2l(data,l); p[sw]=l;
}
@@ -699,7 +706,7 @@ int HASH_UPDATE (HASH_CTX *c, const void *data_, unsigned long len)
l=p[sw];
HOST_p_c2l(data,l,sc);
p[sw++]=l;
- for (; sw < ew; sw++)
+ for (; (sw < ew) && ((data_end - data) >= 4); sw++)
{
HOST_c2l(data,l); p[sw]=l;
}
@@ -755,7 +762,7 @@ int HASH_UPDATE (HASH_CTX *c, const void *data_, unsigned long len)
c->num = (int)len;
ew=(int)(len>>2); /* words to copy */
ec=(int)(len&0x03);
- for (; ew; ew--,p++)
+ for (; ew && ((data_end - data) >= 4); ew--,p++)
{
HOST_c2l(data,l); *p=l;
}
@@ -1048,6 +1055,10 @@ void md5_block_data_order (MD5_CTX *c, const void *data_, int num)
C=c->C;
D=c->D;
+#if defined(__clang_analyzer__)
+ // Get rid of false positive analyzer warning.
+ for (const unsigned char *_ptr = data; _ptr < &data[num * HASH_CBLOCK]; ++_ptr) {}
+#endif
for (; num--;)
{
HOST_c2l(data,l); X( 0)=l; HOST_c2l(data,l); X( 1)=l;
@@ -1283,7 +1294,7 @@ mDNSlocal mDNSs32 DNSDigest_Base64ToBin(const char *src, mDNSu8 *target, mDNSu32
#define HMAC_OPAD 0x5c
#define MD5_LEN 16
-#define HMAC_MD5_AlgName (*(const domainname*) "\010" "hmac-md5" "\007" "sig-alg" "\003" "reg" "\003" "int")
+#define HMAC_MD5_AlgName "\010" "hmac-md5" "\007" "sig-alg" "\003" "reg" "\003" "int"
// Adapted from Appendix, RFC 2104
mDNSlocal void DNSDigest_ConstructHMACKey(DomainAuthInfo *info, const mDNSu8 *key, mDNSu32 len)
@@ -1361,10 +1372,10 @@ mDNSexport void DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, DomainAuthI
MD5_Update(&c, (mDNSu8 *)&tsig.resrec.rroriginalttl, sizeof(tsig.resrec.rroriginalttl));
// alg name
- AssignDomainName(&tsig.resrec.rdata->u.name, &HMAC_MD5_AlgName);
- len = DomainNameLength(&HMAC_MD5_AlgName);
+ AssignConstStringDomainName(&tsig.resrec.rdata->u.name, HMAC_MD5_AlgName);
+ len = DomainNameLengthLimit((domainname *)HMAC_MD5_AlgName, (mDNSu8 *)HMAC_MD5_AlgName + sizeof HMAC_MD5_AlgName);
rdata = tsig.resrec.rdata->u.data + len;
- MD5_Update(&c, HMAC_MD5_AlgName.c, len);
+ MD5_Update(&c, (mDNSu8 *)HMAC_MD5_AlgName, len);
// time
// get UTC (universal time), convert to 48-bit unsigned in network byte order
@@ -1445,7 +1456,7 @@ mDNSexport mDNSBool DNSDigest_VerifyMessage(DNSMessage *msg, mDNSu8 *end, LargeC
algo = (domainname*) ptr;
- if (!SameDomainName(algo, &HMAC_MD5_AlgName))
+ if (!SameDomainName(algo, (domainname *)HMAC_MD5_AlgName))
{
LogMsg("ERROR: DNSDigest_VerifyMessage - TSIG algorithm not supported: %##s", algo->c);
*rcode = kDNSFlag1_RC_NotAuth;
diff --git a/usr/src/contrib/mDNSResponder/mDNSCore/anonymous.c b/usr/src/contrib/mDNSResponder/mDNSCore/anonymous.c
deleted file mode 100644
index 107dc177ac..0000000000
--- a/usr/src/contrib/mDNSResponder/mDNSCore/anonymous.c
+++ /dev/null
@@ -1,623 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2012-2013 Apple Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "mDNSEmbeddedAPI.h"
-#include "CryptoAlg.h"
-#include "anonymous.h"
-#include "DNSCommon.h"
-
-// Define ANONYMOUS_DISABLED to remove all the anonymous functionality
-// and use the stub functions implemented later in this file.
-
-#ifndef ANONYMOUS_DISABLED
-
-#define ANON_NSEC3_ITERATIONS 1
-
-struct AnonInfoResourceRecord_struct
-{
- ResourceRecord resrec;
- RData rdatastorage;
-};
-
-typedef struct AnonInfoResourceRecord_struct AnonInfoResourceRecord;
-
-mDNSlocal mDNSBool InitializeNSEC3Record(ResourceRecord *rr, const mDNSu8 *AnonData, int len, mDNSu32 salt)
-{
- const mDNSu8 *ptr;
- rdataNSEC3 *nsec3 = (rdataNSEC3 *)rr->rdata->u.data;
- mDNSu8 *tmp, *nxt;
- unsigned short iter = ANON_NSEC3_ITERATIONS;
- int hlen;
- const mDNSu8 hashName[NSEC3_MAX_HASH_LEN];
-
- // Construct the RDATA first and construct the owner name based on that.
- ptr = (const mDNSu8 *)&salt;
- debugf("InitializeNSEC3Record: %x%x%x%x, name %##s", ptr[0], ptr[1], ptr[2], ptr[3], rr->name->c);
-
- // Set the RDATA
- nsec3->alg = SHA1_DIGEST_TYPE;
- nsec3->flags = 0;
- nsec3->iterations = swap16(iter);
- nsec3->saltLength = 4;
- tmp = (mDNSu8 *)&nsec3->salt;
- *tmp++ = ptr[0];
- *tmp++ = ptr[1];
- *tmp++ = ptr[2];
- *tmp++ = ptr[3];
-
- // hashLength, nxt, bitmap
- *tmp++ = SHA1_HASH_LENGTH; // hash length
- nxt = tmp;
- tmp += SHA1_HASH_LENGTH;
- *tmp++ = 0; // window number
- *tmp++ = NSEC_MCAST_WINDOW_SIZE; // window length
- mDNSPlatformMemZero(tmp, NSEC_MCAST_WINDOW_SIZE);
- tmp[kDNSType_PTR >> 3] |= 128 >> (kDNSType_PTR & 7);
-
- // Hash the base service name + salt + AnonData
- if (!NSEC3HashName(rr->name, nsec3, AnonData, len, hashName, &hlen))
- {
- LogMsg("InitializeNSEC3Record: NSEC3HashName failed for %##s", rr->name->c);
- return mDNSfalse;
- }
- if (hlen != SHA1_HASH_LENGTH)
- {
- LogMsg("InitializeNSEC3Record: hlen wrong %d", hlen);
- return mDNSfalse;
- }
- mDNSPlatformMemCopy(nxt, hashName, hlen);
-
- return mDNStrue;
-}
-
-mDNSlocal ResourceRecord *ConstructNSEC3Record(const domainname *service, const mDNSu8 *AnonData, int len, mDNSu32 salt)
-{
- ResourceRecord *rr;
- int dlen;
- domainname *name;
-
- // We are just allocating an RData which has StandardAuthRDSize
- if (StandardAuthRDSize < MCAST_NSEC3_RDLENGTH)
- {
- LogMsg("ConstructNSEC3Record: StandardAuthRDSize %d smaller than MCAST_NSEC3_RDLENGTH %d", StandardAuthRDSize, MCAST_NSEC3_RDLENGTH);
- return mDNSNULL;
- }
-
- dlen = DomainNameLength(service);
-
- // Allocate space for the name and RData.
- rr = mDNSPlatformMemAllocate(sizeof(ResourceRecord) + dlen + sizeof(RData));
- if (!rr)
- return mDNSNULL;
- name = (domainname *)((mDNSu8 *)rr + sizeof(ResourceRecord));
- rr->RecordType = kDNSRecordTypePacketAuth;
- rr->InterfaceID = mDNSInterface_Any;
- rr->name = (const domainname *)name;
- rr->rrtype = kDNSType_NSEC3;
- rr->rrclass = kDNSClass_IN;
- rr->rroriginalttl = kStandardTTL;
- rr->rDNSServer = mDNSNULL;
- rr->rdlength = MCAST_NSEC3_RDLENGTH;
- rr->rdestimate = MCAST_NSEC3_RDLENGTH;
- rr->rdata = (RData *)((mDNSu8 *)rr->name + dlen);
-
- AssignDomainName(name, service);
- if (!InitializeNSEC3Record(rr, AnonData, len, salt))
- {
- mDNSPlatformMemFree(rr);
- return mDNSNULL;
- }
- return rr;
-}
-
-mDNSlocal ResourceRecord *CopyNSEC3ResourceRecord(AnonymousInfo *si, const ResourceRecord *rr)
-{
- AnonInfoResourceRecord *anonRR;
- domainname *name;
- mDNSu32 neededLen;
- mDNSu32 extraLen;
-
- if (rr->rdlength < MCAST_NSEC3_RDLENGTH)
- {
- LogMsg("CopyNSEC3ResourceRecord: rdlength %d smaller than MCAST_NSEC3_RDLENGTH %d", rr->rdlength, MCAST_NSEC3_RDLENGTH);
- return mDNSNULL;
- }
- // Allocate space for the name and the rdata along with the ResourceRecord
- neededLen = rr->rdlength + DomainNameLength(rr->name);
- extraLen = (neededLen > sizeof(RDataBody)) ? (neededLen - sizeof(RDataBody)) : 0;
- anonRR = (AnonInfoResourceRecord *)mDNSPlatformMemAllocate(sizeof(AnonInfoResourceRecord) + extraLen);
- if (!anonRR)
- return mDNSNULL;
-
- anonRR->resrec = *rr;
-
- anonRR->rdatastorage.MaxRDLength = rr->rdlength;
- mDNSPlatformMemCopy(anonRR->rdatastorage.u.data, rr->rdata->u.data, rr->rdlength);
-
- name = (domainname *)(anonRR->rdatastorage.u.data + rr->rdlength);
- AssignDomainName(name, rr->name);
-
- anonRR->resrec.name = name;
- anonRR->resrec.rdata = &anonRR->rdatastorage;
-
- si->nsec3RR = (ResourceRecord *)anonRR;
-
- return si->nsec3RR;
-}
-
-// When a service is started or a browse is started with the Anonymous data, we allocate a new random
-// number and based on that allocate a new NSEC3 resource record whose hash is a function of random number (salt) and
-// the anonymous data.
-//
-// If we receive a packet with the NSEC3 option, we need to cache that along with the resource record so that we can
-// check against the question to see whether it answers them or not. In that case, we pass the "rr" that we received.
-mDNSexport AnonymousInfo *AllocateAnonInfo(const domainname *service, const mDNSu8 *data, int len, const ResourceRecord *rr)
-{
- AnonymousInfo *ai;
- ai = (AnonymousInfo *)mDNSPlatformMemAllocate(sizeof(AnonymousInfo));
- if (!ai)
- {
- return mDNSNULL;
- }
- mDNSPlatformMemZero(ai, sizeof(AnonymousInfo));
- if (rr)
- {
- if (!CopyNSEC3ResourceRecord(ai, rr))
- {
- mDNSPlatformMemFree(ai);
- return mDNSNULL;
- }
- return ai;
- }
- ai->salt = mDNSRandom(0xFFFFFFFF);
- ai->AnonData = mDNSPlatformMemAllocate(len);
- if (!ai->AnonData)
- {
- mDNSPlatformMemFree(ai);
- return mDNSNULL;
- }
- ai->AnonDataLen = len;
- mDNSPlatformMemCopy(ai->AnonData, data, len);
- ai->nsec3RR = ConstructNSEC3Record(service, data, len, ai->salt);
- if (!ai->nsec3RR)
- {
- mDNSPlatformMemFree(ai);
- return mDNSNULL;
- }
- return ai;
-}
-
-mDNSexport void FreeAnonInfo(AnonymousInfo *ai)
-{
- if (ai->nsec3RR)
- mDNSPlatformMemFree(ai->nsec3RR);
- if (ai->AnonData)
- mDNSPlatformMemFree(ai->AnonData);
- mDNSPlatformMemFree(ai);
-}
-
-mDNSexport void ReInitAnonInfo(AnonymousInfo **AnonInfo, const domainname *name)
-{
- if (*AnonInfo)
- {
- AnonymousInfo *ai = *AnonInfo;
- *AnonInfo = AllocateAnonInfo(name, ai->AnonData, ai->AnonDataLen, mDNSNULL);
- if (!(*AnonInfo))
- *AnonInfo = ai;
- else
- FreeAnonInfo(ai);
- }
-}
-
-// This function should be used only if you know that the question and
-// the resource record belongs to the same set. The main usage is
-// in ProcessQuery where we find the question to be part of the same
-// set as the resource record, but it needs the AnonData to be
-// initialized so that it can walk the cache records to see if they
-// answer the question.
-mDNSexport void SetAnonData(DNSQuestion *q, ResourceRecord *rr, mDNSBool ForQuestion)
-{
- if (!q->AnonInfo || !rr->AnonInfo)
- {
- LogMsg("SetAnonData: question %##s(%p), rr %##s(%p), NULL", q->qname.c, q->AnonInfo, rr->name->c, rr->AnonInfo);
- return;
- }
-
- debugf("SetAnonData: question %##s(%p), rr %##s(%p)", q->qname.c, q->AnonInfo, rr->name->c, rr->AnonInfo);
- if (ForQuestion)
- {
- if (q->AnonInfo->AnonDataLen < rr->AnonInfo->AnonDataLen)
- {
- mDNSPlatformMemFree(q->AnonInfo->AnonData);
- q->AnonInfo->AnonData = mDNSNULL;
- }
-
- if (!q->AnonInfo->AnonData)
- {
- q->AnonInfo->AnonData = mDNSPlatformMemAllocate(rr->AnonInfo->AnonDataLen);
- if (!q->AnonInfo->AnonData)
- return;
- }
- mDNSPlatformMemCopy(q->AnonInfo->AnonData, rr->AnonInfo->AnonData, rr->AnonInfo->AnonDataLen);
- q->AnonInfo->AnonDataLen = rr->AnonInfo->AnonDataLen;
- }
- else
- {
- if (rr->AnonInfo->AnonDataLen < q->AnonInfo->AnonDataLen)
- {
- mDNSPlatformMemFree(rr->AnonInfo->AnonData);
- rr->AnonInfo->AnonData = mDNSNULL;
- }
-
- if (!rr->AnonInfo->AnonData)
- {
- rr->AnonInfo->AnonData = mDNSPlatformMemAllocate(q->AnonInfo->AnonDataLen);
- if (!rr->AnonInfo->AnonData)
- return;
- }
- mDNSPlatformMemCopy(rr->AnonInfo->AnonData, q->AnonInfo->AnonData, q->AnonInfo->AnonDataLen);
- rr->AnonInfo->AnonDataLen = q->AnonInfo->AnonDataLen;
- }
-}
-
-// returns -1 if the caller should ignore the result
-// returns 1 if the record answers the question
-// returns 0 if the record does not answer the question
-mDNSexport int AnonInfoAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
-{
- mDNSexport mDNS mDNSStorage;
- ResourceRecord *nsec3RR;
- int i;
- AnonymousInfo *qai, *rai;
- mDNSu8 *AnonData;
- int AnonDataLen;
- rdataNSEC3 *nsec3;
- int hlen;
- int nxtLength;
- mDNSu8 *nxtName;
- mDNSu8 hashName[NSEC3_MAX_HASH_LEN];
- mDNSPlatformMemZero(hashName, sizeof(hashName));
-
- debugf("AnonInfoAnswersQuestion: question qname %##s", q->qname.c);
-
- // Currently only PTR records can have anonymous information
- if (q->qtype != kDNSType_PTR)
- {
- return -1;
- }
-
- // We allow anonymous questions to be answered by both normal services (without the
- // anonymous information) and anonymous services that are part of the same set. And
- // normal questions discover normal services and all anonymous services.
- //
- // The three cases have been enumerated clearly even though they all behave the
- // same way.
- if (!q->AnonInfo)
- {
- debugf("AnonInfoAnswersQuestion: not a anonymous type question");
- if (!rr->AnonInfo)
- {
- // case 1
- return -1;
- }
- else
- {
- // case 2
- debugf("AnonInfoAnswersQuestion: Question %##s not answered using anonymous record %##s", q->qname.c, rr->name->c);
- return -1;
- }
- }
- else
- {
- // case 3
- if (!rr->AnonInfo)
- {
- debugf("AnonInfoAnswersQuestion: not a anonymous type record");
- return -1;
- }
- }
-
- // case 4: We have the anonymous information both in the question and the record. We need
- // two sets of information to validate.
- //
- // 1) Anonymous data that identifies the set/group
- // 2) NSEC3 record that contains the hash and the salt
- //
- // If the question is a remote one, it does not have the anonymous information to validate (just
- // the NSEC3 record) and hence the anonymous data should come from the local resource record. If the
- // question is local, it can come from either of them and if there is a mismatch between the
- // question and record, it won't validate.
-
- qai = q->AnonInfo;
- rai = rr->AnonInfo;
-
- if (qai->AnonData && rai->AnonData)
- {
- // Before a cache record is created, if there is a matching question i.e., part
- // of the same set, then when the cache is created we also set the anonymous
- // information. Otherwise, the cache record contains just the NSEC3 record and we
- // won't be here for that case.
- //
- // It is also possible that a local question is matched against the local AuthRecord
- // as that is also the case for which the AnonData would be non-NULL for both.
- // We match questions against AuthRecords (rather than the cache) for LocalOnly case and
- // to see whether a .local query should be suppressed or not. The latter never happens
- // because PTR queries are never suppressed.
-
- // If they don't belong to the same anonymous set, then no point in validating.
- if ((qai->AnonDataLen != rai->AnonDataLen) ||
- mDNSPlatformMemCmp(qai->AnonData, rai->AnonData, qai->AnonDataLen) != 0)
- {
- debugf("AnonInfoAnswersQuestion: AnonData mis-match for record %s question %##s ",
- RRDisplayString(&mDNSStorage, rr), q->qname.c);
- return 0;
- }
- // AnonData matches i.e they belong to the same group and the same service.
- LogInfo("AnonInfoAnswersQuestion: Answering qname %##s, rname %##s, without validation", q->qname.c,
- rr->name->c);
- return 1;
- }
- else
- {
- debugf("AnonInfoAnswersQuestion: question %p, record %p", qai->AnonData, rai->AnonData);
- }
-
- if (qai->AnonData)
- {
- // If there is AnonData, then this is a local question. The
- // NSEC3 RR comes from the resource record which could be part
- // of the cache or local auth record. The cache entry could
- // be from a remote host or created when we heard our own
- // announcements. In any case, we use that to see if it matches
- // the question.
- AnonData = qai->AnonData;
- AnonDataLen = qai->AnonDataLen;
- nsec3RR = rai->nsec3RR;
- }
- else
- {
- // Remote question or hearing our own question back
- AnonData = rai->AnonData;
- AnonDataLen = rai->AnonDataLen;
- nsec3RR = qai->nsec3RR;
- }
-
- if (!AnonData || !nsec3RR)
- {
- // AnonData can be NULL for the cache entry and if we are hearing our own question back, AnonData is NULL for
- // that too and we can end up here for that case.
- debugf("AnonInfoAnswersQuestion: AnonData %p or nsec3RR %p, NULL for question %##s, record %s", AnonData, nsec3RR,
- q->qname.c, RRDisplayString(&mDNSStorage, rr));
- return 0;
- }
- debugf("AnonInfoAnswersQuestion: Validating question %##s, ResourceRecord %s", q->qname.c, RRDisplayString(&mDNSStorage, nsec3RR));
-
-
- nsec3 = (rdataNSEC3 *)nsec3RR->rdata->u.data;
-
- if (!NSEC3HashName(nsec3RR->name, nsec3, AnonData, AnonDataLen, hashName, &hlen))
- {
- LogMsg("AnonInfoAnswersQuestion: NSEC3HashName failed for %##s", nsec3RR->name->c);
- return mDNSfalse;
- }
- if (hlen != SHA1_HASH_LENGTH)
- {
- LogMsg("AnonInfoAnswersQuestion: hlen wrong %d", hlen);
- return mDNSfalse;
- }
-
- NSEC3Parse(nsec3RR, mDNSNULL, &nxtLength, &nxtName, mDNSNULL, mDNSNULL);
-
- if (hlen != nxtLength)
- {
- LogMsg("AnonInfoAnswersQuestion: ERROR!! hlen %d not same as nxtLength %d", hlen, nxtLength);
- return mDNSfalse;
- }
-
- for (i = 0; i < nxtLength; i++)
- {
- if (nxtName[i] != hashName[i])
- {
- debugf("AnonInfoAnswersQuestion: mismatch output %x, digest %x, i %d", nxtName[i+1], hashName[i], i);
- return 0;
- }
- }
- LogInfo("AnonInfoAnswersQuestion: ResourceRecord %s matched question %##s (%s)", RRDisplayString(&mDNSStorage, nsec3RR), q->qname.c, DNSTypeName(q->qtype));
- return 1;
-}
-
-// Find a matching NSEC3 record for the name. We parse the questions and the records in the packet in order.
-// Similarly we also parse the NSEC3 records in order and this mapping to the questions and records
-// respectively.
-mDNSlocal CacheRecord *FindMatchingNSEC3ForName(mDNS *const m, CacheRecord **nsec3, const domainname *name)
-{
- CacheRecord *cr;
- CacheRecord **prev = nsec3;
-
- (void) m;
-
- for (cr = *nsec3; cr; cr = cr->next)
- {
- if (SameDomainName(cr->resrec.name, name))
- {
- debugf("FindMatchingNSEC3ForName: NSEC3 record %s matched %##s", CRDisplayString(m, cr), name->c);
- *prev = cr->next;
- cr->next = mDNSNULL;
- return cr;
- }
- prev = &cr->next;
- }
- return mDNSNULL;
-}
-
-mDNSexport void InitializeAnonInfoForQuestion(mDNS *const m, CacheRecord **McastNSEC3Records, DNSQuestion *q)
-{
- CacheRecord *nsec3CR;
-
- if (q->qtype != kDNSType_PTR)
- return;
-
- nsec3CR = FindMatchingNSEC3ForName(m, McastNSEC3Records, &q->qname);
- if (nsec3CR)
- {
- q->AnonInfo = AllocateAnonInfo(mDNSNULL, mDNSNULL, 0, &nsec3CR->resrec);
- if (q->AnonInfo)
- {
- debugf("InitializeAnonInfoForQuestion: Found a matching NSEC3 record %s, for %##s (%s)",
- RRDisplayString(m, q->AnonInfo->nsec3RR), q->qname.c, DNSTypeName(q->qtype));
- }
- ReleaseCacheRecord(m, nsec3CR);
- }
-}
-
-mDNSexport void InitializeAnonInfoForCR(mDNS *const m, CacheRecord **McastNSEC3Records, CacheRecord *cr)
-{
- CacheRecord *nsec3CR;
-
- if (!(*McastNSEC3Records))
- return;
-
- // If already initialized or not a PTR type, we don't have to do anything
- if (cr->resrec.AnonInfo || cr->resrec.rrtype != kDNSType_PTR)
- return;
-
- nsec3CR = FindMatchingNSEC3ForName(m, McastNSEC3Records, cr->resrec.name);
- if (nsec3CR)
- {
- cr->resrec.AnonInfo = AllocateAnonInfo(mDNSNULL, mDNSNULL, 0, &nsec3CR->resrec);
- if (cr->resrec.AnonInfo)
- {
- debugf("InitializeAnonInfoForCR: Found a matching NSEC3 record %s, for %##s (%s)",
- RRDisplayString(m, cr->resrec.AnonInfo->nsec3RR), cr->resrec.name->c,
- DNSTypeName(cr->resrec.rrtype));
- }
- ReleaseCacheRecord(m, nsec3CR);
- }
-}
-
-mDNSexport mDNSBool IdenticalAnonInfo(AnonymousInfo *a1, AnonymousInfo *a2)
-{
- // if a1 is NULL and a2 is not NULL AND vice-versa
- // return false as there is a change.
- if ((a1 != mDNSNULL) != (a2 != mDNSNULL))
- return mDNSfalse;
-
- // Both could be NULL or non-NULL
- if (a1 && a2)
- {
- // The caller already verified that the owner name is the same.
- // Check whether the RData is same.
- if (!IdenticalSameNameRecord(a1->nsec3RR, a2->nsec3RR))
- {
- debugf("IdenticalAnonInfo: nsec3RR mismatch");
- return mDNSfalse;
- }
- }
- return mDNStrue;
-}
-
-mDNSexport void CopyAnonInfoForCR(mDNS *const m, CacheRecord *crto, CacheRecord *crfrom)
-{
- AnonymousInfo *aifrom = crfrom->resrec.AnonInfo;
- AnonymousInfo *aito = crto->resrec.AnonInfo;
-
- (void) m;
-
- if (!aifrom)
- return;
-
- if (aito)
- {
- crto->resrec.AnonInfo = aifrom;
- FreeAnonInfo(aito);
- crfrom->resrec.AnonInfo = mDNSNULL;
- }
- else
- {
- FreeAnonInfo(aifrom);
- crfrom->resrec.AnonInfo = mDNSNULL;
- }
-}
-
-#else // !ANONYMOUS_DISABLED
-
-mDNSexport void ReInitAnonInfo(AnonymousInfo **si, const domainname *name)
-{
- (void)si;
- (void)name;
-}
-
-mDNSexport AnonymousInfo * AllocateAnonInfo(const domainname *service, const mDNSu8 *AnonData, int len, const ResourceRecord *rr)
-{
- (void)service;
- (void)AnonData;
- (void)len;
- (void)rr;
-
- return mDNSNULL;
-}
-
-mDNSexport void FreeAnonInfo(AnonymousInfo *ai)
-{
- (void)ai;
-}
-
-mDNSexport void SetAnonData(DNSQuestion *q, ResourceRecord *rr, mDNSBool ForQuestion)
-{
- (void)q;
- (void)rr;
- (void)ForQuestion;
-}
-
-mDNSexport int AnonInfoAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
-{
- (void)rr;
- (void)q;
-
- return mDNSfalse;
-}
-
-mDNSexport void InitializeAnonInfoForQuestion(mDNS *const m, CacheRecord **McastNSEC3Records, DNSQuestion *q)
-{
- (void)m;
- (void)McastNSEC3Records;
- (void)q;
-}
-
-mDNSexport void InitializeAnonInfoForCR(mDNS *const m, CacheRecord **McastNSEC3Records, CacheRecord *cr)
-{
- (void)m;
- (void)McastNSEC3Records;
- (void)cr;
-}
-
-mDNSexport void CopyAnonInfoForCR(mDNS *const m, CacheRecord *crto, CacheRecord *crfrom)
-{
- (void)m;
- (void)crto;
- (void)crfrom;
-}
-
-mDNSexport mDNSBool IdenticalAnonInfo(AnonymousInfo *a1, AnonymousInfo *a2)
-{
- (void)a1;
- (void)a2;
-
- return mDNStrue;
-}
-
-#endif // !ANONYMOUS_DISABLED
diff --git a/usr/src/contrib/mDNSResponder/mDNSCore/anonymous.h b/usr/src/contrib/mDNSResponder/mDNSCore/anonymous.h
deleted file mode 100644
index b60812ea0d..0000000000
--- a/usr/src/contrib/mDNSResponder/mDNSCore/anonymous.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2012 Apple Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __ANONYMOUS_H_
-#define __ANONYMOUS_H_
-
-extern void ReInitAnonInfo(AnonymousInfo **si, const domainname *name);
-extern AnonymousInfo *AllocateAnonInfo(const domainname *service, const mDNSu8 *AnonData, int len, const ResourceRecord *rr);
-extern void FreeAnonInfo(AnonymousInfo *ai);
-extern void SetAnonData(DNSQuestion *q, ResourceRecord *rr, mDNSBool ForQuestion);
-extern int AnonInfoAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
-extern void InitializeAnonInfoForCR(mDNS *const m, CacheRecord **McastNSEC3Records, CacheRecord *cr);
-extern void InitializeAnonInfoForQuestion(mDNS *const m, CacheRecord **McastNSEC3Records, DNSQuestion *q);
-extern void CopyAnonInfoForCR(mDNS *const m, CacheRecord *crto, CacheRecord *crfrom);
-extern mDNSBool IdenticalAnonInfo(AnonymousInfo *a1, AnonymousInfo *a2);
-
-#endif
diff --git a/usr/src/contrib/mDNSResponder/mDNSCore/dnsproxy.h b/usr/src/contrib/mDNSResponder/mDNSCore/dnsproxy.h
index 7008c058da..dcb7d55faf 100644
--- a/usr/src/contrib/mDNSResponder/mDNSCore/dnsproxy.h
+++ b/usr/src/contrib/mDNSResponder/mDNSCore/dnsproxy.h
@@ -1,6 +1,6 @@
/* -*- Mode: C; tab-width: 4 -*-
*
- * Copyright (c) 2011-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2011-2020 Apple Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,8 +24,13 @@
extern void ProxyUDPCallback(void *socket, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr,
const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, void *context);
extern void ProxyTCPCallback(void *socket, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr,
- const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, void *context);
+ const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, void *context);
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNS_PROXY_DNS64)
+extern void DNSProxyInit(mDNSu32 IpIfArr[MaxIp], mDNSu32 OpIf, const mDNSu8 IPv6Prefix[16], int IPv6PrefixLen,
+ mDNSBool alwaysSynthesize);
+#else
extern void DNSProxyInit(mDNSu32 IpIfArr[MaxIp], mDNSu32 OpIf);
+#endif
extern void DNSProxyTerminate(void);
#endif // __DNS_PROXY_H
diff --git a/usr/src/contrib/mDNSResponder/mDNSCore/dnssec.h b/usr/src/contrib/mDNSResponder/mDNSCore/dnssec.h
deleted file mode 100644
index b770af8de0..0000000000
--- a/usr/src/contrib/mDNSResponder/mDNSCore/dnssec.h
+++ /dev/null
@@ -1,158 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2011-2013 Apple Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __DNSSEC_H
-#define __DNSSEC_H
-
-#include "CryptoAlg.h"
-#include "mDNSDebug.h"
-
-typedef enum
-{
- RRVS_rr, RRVS_rrsig, RRVS_key, RRVS_rrsig_key, RRVS_ds, RRVS_done,
-} RRVerifierSet;
-
-typedef struct RRVerifier_struct RRVerifier;
-typedef struct DNSSECVerifier_struct DNSSECVerifier;
-typedef struct AuthChain_struct AuthChain;
-typedef struct InsecureContext_struct InsecureContext;
-
-struct RRVerifier_struct
-{
- RRVerifier *next;
- mDNSu16 rrtype;
- mDNSu16 rrclass;
- mDNSu32 rroriginalttl;
- mDNSu16 rdlength;
- mDNSu16 found;
- mDNSu32 namehash;
- mDNSu32 rdatahash;
- domainname name;
- mDNSu8 *rdata;
-};
-
-// Each AuthChain element has one rrset (with multiple resource records of same type), rrsig and key
-// that validates the rrset.
-struct AuthChain_struct
-{
- AuthChain *next; // Next element in the chain
- RRVerifier *rrset; // RRSET that is authenticated
- RRVerifier *rrsig; // Signature for that RRSET
- RRVerifier *key; // Public key for that RRSET
-};
-
-#define ResetAuthChain(dv) { \
- (dv)->ac = mDNSNULL; \
- (dv)->actail = &((dv)->ac); \
-}
-
-typedef void DNSSECVerifierCallback (mDNS *const m, DNSSECVerifier *dv, DNSSECStatus status);
-//
-// When we do a validation for a question, there might be additional validations that needs to be done e.g.,
-// wildcard expanded answer. It is also possible that in the case of nsec we need to prove both that a wildcard
-// does not apply and the closest encloser proves that name does not exist. We identify these with the following
-// flags.
-//
-// Note: In the following, by "marking the validation", we mean that as part of validation we need to prove
-// the ones that are marked with.
-//
-// A wildcard may be used to answer a question. In that case, we need to verify that the right wildcard was
-// used in answering the question. This is done by marking the validation with WILDCARD_PROVES_ANSWER_EXPANDED.
-//
-// Sometimes we get a NXDOMAIN response. In this case, we may have a wildcard where we need to prove
-// that the wildcard proves that the name does not exist. This is done by marking the validation with
-// WILDCARD_PROVES_NONAME_EXISTS.
-//
-// In the case of NODATA error, sometimes the name may exist but the query type does not exist. This is done by
-// marking the validation with NSEC_PROVES_NOTYPE_EXISTS.
-//
-// In both NXDOMAIN and NODATA proofs, we may have to prove that the NAME does not exist. This is done by marking
-// the validation with NSEC_PROVES_NONAME_EXISTS.
-//
-#define WILDCARD_PROVES_ANSWER_EXPANDED 0x00000001
-#define WILDCARD_PROVES_NONAME_EXISTS 0x00000002
-#define NSEC_PROVES_NOTYPE_EXISTS 0x00000004
-#define NSEC_PROVES_NONAME_EXISTS 0x00000008
-#define NSEC3_OPT_OUT 0x00000010 // OptOut was set in NSEC3
-
-struct DNSSECVerifier_struct
-{
- domainname origName; // Original question name that needs verification
- mDNSu16 origType; // Original question type corresponding to origName
- mDNSu16 currQtype; // Current question type that is being verified
- mDNSInterfaceID InterfaceID; // InterfaceID of the question
- DNSQuestion q;
- mDNSu8 recursed; // Number of times recursed during validation
- mDNSu8 ValidationRequired; // Copy of the question's ValidationRequired status
- mDNSu8 InsecureProofDone;
- mDNSu8 NumPackets; // Number of packets that we send on the wire for DNSSEC verification.
- mDNSs32 StartTime; // Time the DNSSEC verification starts
- mDNSu32 flags;
- RRVerifierSet next;
- domainname *wildcardName; // set if the answer is wildcard expanded
- RRVerifier *pendingNSEC;
- DNSSECVerifierCallback *DVCallback;
- DNSSECVerifier *parent;
- RRVerifier *rrset; // rrset for which we have to verify
- RRVerifier *rrsig; // RRSIG for rrset
- RRVerifier *key; // DNSKEY for rrset
- RRVerifier *rrsigKey; // RRSIG for DNSKEY
- RRVerifier *ds; // DS for DNSKEY set in parent zone
- AuthChain *saveac;
- AuthChain *ac;
- AuthChain **actail;
- AlgContext *ctx;
-};
-
-
-struct InsecureContext_struct
-{
- DNSSECVerifier *dv; // dv for which we are doing the insecure proof
- mDNSu8 skip; // labels to skip for forming the name from origName
- DNSSECStatus status; // status to deliver when done
- mDNSu8 triggerLabelCount; // Label count of the name that triggered the insecure proof
- DNSQuestion q;
-};
-
-#define LogDNSSEC LogOperation
-
-#define DNS_SERIAL_GT(a, b) ((int)((a) - (b)) > 0)
-#define DNS_SERIAL_LT(a, b) ((int)((a) - (b)) < 0)
-
-extern void StartDNSSECVerification(mDNS *const m, void *context);
-extern RRVerifier* AllocateRRVerifier(const ResourceRecord *const rr, mStatus *status);
-extern mStatus AddRRSetToVerifier(DNSSECVerifier *dv, const ResourceRecord *const rr, RRVerifier *rv, RRVerifierSet set);
-extern void VerifySignature(mDNS *const m, DNSSECVerifier *dv, DNSQuestion *q);
-extern void FreeDNSSECVerifier(mDNS *const m, DNSSECVerifier *dv);
-extern DNSSECVerifier *AllocateDNSSECVerifier(mDNS *const m, const domainname *name, mDNSu16 rrtype, mDNSInterfaceID InterfaceID,
- mDNSu8 ValidationRequired, DNSSECVerifierCallback dvcallback, mDNSQuestionCallback qcallback);
-extern void InitializeQuestion(mDNS *const m, DNSQuestion *question, mDNSInterfaceID InterfaceID, const domainname *qname,
- mDNSu16 qtype, mDNSQuestionCallback *callback, void *context);
-extern void ValidateRRSIG(DNSSECVerifier *dv, RRVerifierSet type, const ResourceRecord *const rr);
-extern void AuthChainLink(DNSSECVerifier *dv, AuthChain *ae);
-extern mStatus DNSNameToLowerCase(domainname *d, domainname *result);
-extern int DNSMemCmp(const mDNSu8 *const m1, const mDNSu8 *const m2, int len);
-extern int DNSSECCanonicalOrder(const domainname *const d1, const domainname *const d2, int *subdomain);
-extern void ProveInsecure(mDNS *const m, DNSSECVerifier *dv, InsecureContext *ic, domainname *trigger);
-extern void BumpDNSSECStats(mDNS *const m, DNSSECStatsAction action, DNSSECStatsType type, mDNSu32 value);
-extern char *DNSSECStatusName(DNSSECStatus status);
-
-// DNSSECProbe belongs in DNSSECSupport.h but then we don't want to expose yet another plaform specific dnssec file
-// to other platforms where dnssec is not supported.
-extern void DNSSECProbe(mDNS *const m);
-
-#endif // __DNSSEC_H
diff --git a/usr/src/contrib/mDNSResponder/mDNSCore/mDNS.c b/usr/src/contrib/mDNSResponder/mDNSCore/mDNS.c
index 0d94aae681..bc51cc4144 100755
--- a/usr/src/contrib/mDNSResponder/mDNSCore/mDNS.c
+++ b/usr/src/contrib/mDNSResponder/mDNSCore/mDNS.c
@@ -1,6 +1,6 @@
-/* -*- Mode: C; tab-width: 4 -*-
+/* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*-
*
- * Copyright (c) 2002-2018 Apple Inc. All rights reserved.
+ * Copyright (c) 2002-2020 Apple Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,9 +25,22 @@
#include "DNSCommon.h" // Defines general DNS utility routines
#include "uDNS.h" // Defines entry points into unicast-specific routines
-#include "nsec.h"
-#include "dnssec.h"
-#include "anonymous.h"
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+#include "D2D.h"
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
+#include <bsm/libbsm.h>
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, CACHE_ANALYTICS)
+#include "dnssd_analytics.h"
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+#include "QuerierSupport.h"
+#endif
// Disable certain benign warnings with Microsoft compilers
#if (defined(_MSC_VER))
@@ -48,54 +61,49 @@
#include "dns_sd_internal.h"
#if APPLE_OSX_mDNSResponder
-#include <WebFilterDNS/WebFilterDNS.h>
-
// Delay in seconds before disabling multicast after there are no active queries or registrations.
#define BONJOUR_DISABLE_DELAY 60
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
+#include <WebFilterDNS/WebFilterDNS.h>
-#if !NO_WCF
WCFConnection *WCFConnectionNew(void) __attribute__((weak_import));
void WCFConnectionDealloc(WCFConnection* c) __attribute__((weak_import));
+#endif
-// Do we really need to define a macro for "if"?
-#define CHECK_WCF_FUNCTION(X) if (X)
-#endif // ! NO_WCF
-
-#else
-
-#define NO_WCF 1
-#endif // APPLE_OSX_mDNSResponder
-
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
#include "Metrics.h"
#endif
-#if USE_DNS64
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
#include "DNS64.h"
#endif
-#ifdef UNIT_TEST
-#include "unittest.h"
-#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+#include "dnssec_v2.h"
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
// Forward declarations
mDNSlocal void BeginSleepProcessing(mDNS *const m);
mDNSlocal void RetrySPSRegistrations(mDNS *const m);
mDNSlocal void SendWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAddr *EthAddr, mDNSOpaque48 *password, mDNSBool unicastOnly);
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
mDNSlocal mDNSBool LocalRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q);
+#endif
mDNSlocal void mDNS_PurgeBeforeResolve(mDNS *const m, DNSQuestion *q);
-mDNSlocal void CheckForDNSSECRecords(mDNS *const m, DNSQuestion *q);
mDNSlocal void mDNS_SendKeepalives(mDNS *const m);
mDNSlocal void mDNS_ExtractKeepaliveInfo(AuthRecord *ar, mDNSu32 *timeout, mDNSAddr *laddr, mDNSAddr *raddr, mDNSEthAddr *eth,
mDNSu32 *seq, mDNSu32 *ack, mDNSIPPort *lport, mDNSIPPort *rport, mDNSu16 *win);
-mDNSlocal void AdvertiseAllInterfaceRecords(mDNS *const m);
-mDNSlocal void DeadvertiseAllInterfaceRecords(mDNS *const m);
-mDNSlocal void FreeNSECRecords(mDNS *const m, CacheRecord *NSECRecords);
-mDNSlocal void mDNSParseNSEC3Records(mDNS *const m, const DNSMessage *const response, const mDNSu8 *end,
- const mDNSInterfaceID InterfaceID, CacheRecord **NSEC3Records);
-mDNSlocal mDNSu8 *GetValueForMACAddr(mDNSu8 *ptr, mDNSu8 *limit, mDNSEthAddr *eth);
+typedef mDNSu32 DeadvertiseFlags;
+#define kDeadvertiseFlag_NormalHostname (1U << 0)
+#define kDeadvertiseFlag_RandHostname (1U << 1)
+#define kDeadvertiseFlag_All (kDeadvertiseFlag_NormalHostname | kDeadvertiseFlag_RandHostname)
+mDNSlocal void DeadvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set, DeadvertiseFlags flags);
+mDNSlocal void AdvertiseInterfaceIfNeeded(mDNS *const m, NetworkInterfaceInfo *set);
+mDNSlocal mDNSu8 *GetValueForMACAddr(mDNSu8 *ptr, mDNSu8 *limit, mDNSEthAddr *eth);
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
@@ -105,8 +113,6 @@ mDNSlocal mDNSu8 *GetValueForMACAddr(mDNSu8 *ptr, mDNSu8 *limit, mDNSEthAddr *et
// To Turn OFF mDNS_Tracer set MDNS_TRACER to 0 or undef it
#define MDNS_TRACER 1
-#define NO_HINFO 1
-
// Any records bigger than this are considered 'large' records
#define SmallRecordLimit 1024
@@ -174,8 +180,89 @@ mDNSexport const char *const mDNS_DomainTypeNames[] =
#pragma mark - General Utility Functions
#endif
-// Returns true if this is a unique, authoritative LocalOnly record that answers questions of type
-// A, AAAA , CNAME, or PTR. The caller should answer the question with this record and not send out
+#if MDNS_MALLOC_DEBUGGING
+// When doing memory allocation debugging, this function traverses all lists in the mDNS query
+// structures and caches and checks each entry in the list to make sure it's still good.
+mDNSlocal void mDNS_ValidateLists(void *context)
+{
+ mDNS *m = context;
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
+ mDNSu32 NumAllInterfaceRecords = 0;
+ mDNSu32 NumAllInterfaceQuestions = 0;
+#endif
+
+ // Check core mDNS lists
+ AuthRecord *rr;
+ for (rr = m->ResourceRecords; rr; rr=rr->next)
+ {
+ if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
+ LogMemCorruption("ResourceRecords list: %p is garbage (%X)", rr, rr->resrec.RecordType);
+ if (rr->resrec.name != &rr->namestorage)
+ LogMemCorruption("ResourceRecords list: %p name %p does not point to namestorage %p %##s",
+ rr, rr->resrec.name->c, rr->namestorage.c, rr->namestorage.c);
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
+ if (!AuthRecord_uDNS(rr) && !RRLocalOnly(rr)) NumAllInterfaceRecords++;
+#endif
+ }
+
+ for (rr = m->DuplicateRecords; rr; rr=rr->next)
+ {
+ if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
+ LogMemCorruption("DuplicateRecords list: %p is garbage (%X)", rr, rr->resrec.RecordType);
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
+ if (!AuthRecord_uDNS(rr) && !RRLocalOnly(rr)) NumAllInterfaceRecords++;
+#endif
+ }
+
+ rr = m->NewLocalRecords;
+ if (rr)
+ if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
+ LogMemCorruption("NewLocalRecords: %p is garbage (%X)", rr, rr->resrec.RecordType);
+
+ rr = m->CurrentRecord;
+ if (rr)
+ if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
+ LogMemCorruption("CurrentRecord: %p is garbage (%X)", rr, rr->resrec.RecordType);
+
+ DNSQuestion *q;
+ for (q = m->Questions; q; q=q->next)
+ {
+ if (q->next == (DNSQuestion*)~0 || q->ThisQInterval == (mDNSs32) ~0)
+ LogMemCorruption("Questions list: %p is garbage (%lX %p)", q, q->ThisQInterval, q->next);
+ if (q->DuplicateOf && q->LocalSocket)
+ LogMemCorruption("Questions list: Duplicate Question %p should not have LocalSocket set %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
+ if (!LocalOnlyOrP2PInterface(q->InterfaceID) && mDNSOpaque16IsZero(q->TargetQID))
+ NumAllInterfaceQuestions++;
+#endif
+ }
+
+ CacheGroup *cg;
+ CacheRecord *cr;
+ mDNSu32 slot;
+ FORALL_CACHERECORDS(slot, cg, cr)
+ {
+ if (cr->resrec.RecordType == 0 || cr->resrec.RecordType == 0xFF)
+ LogMemCorruption("Cache slot %lu: %p is garbage (%X)", slot, cr, cr->resrec.RecordType);
+ if (cr->CRActiveQuestion)
+ {
+ for (q = m->Questions; q; q=q->next) if (q == cr->CRActiveQuestion) break;
+ if (!q) LogMemCorruption("Cache slot %lu: CRActiveQuestion %p not in m->Questions list %s", slot, cr->CRActiveQuestion, CRDisplayString(m, cr));
+ }
+ }
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
+ if (m->NumAllInterfaceRecords != NumAllInterfaceRecords)
+ LogMemCorruption("NumAllInterfaceRecords is %d should be %d", m->NumAllInterfaceRecords, NumAllInterfaceRecords);
+
+ if (m->NumAllInterfaceQuestions != NumAllInterfaceQuestions)
+ LogMemCorruption("NumAllInterfaceQuestions is %d should be %d", m->NumAllInterfaceQuestions, NumAllInterfaceQuestions);
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
+}
+#endif // MDNS_MALLOC_DEBUGGING
+
+// Returns true if this is a unique, authoritative LocalOnly record that answers questions of type
+// A, AAAA , CNAME, or PTR. The caller should answer the question with this record and not send out
// the question on the wire if LocalOnlyRecordAnswersQuestion() also returns true.
// Main use is to handle /etc/hosts records and the LocalOnly PTR records created for localhost.
#define UniqueLocalOnlyRecord(rr) ((rr)->ARType == AuthRecordLocalOnly && \
@@ -209,7 +296,7 @@ mDNSexport void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q)
mDNSlocal void ReleaseAuthEntity(AuthHash *r, AuthEntity *e)
{
-#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1
+#if MDNS_MALLOC_DEBUGGING >= 1
unsigned int i;
for (i=0; i<sizeof(*e); i++) ((char*)e)[i] = 0xFF;
#endif
@@ -243,7 +330,7 @@ mDNSlocal AuthEntity *GetAuthEntity(AuthHash *r, const AuthGroup *const Preserve
// free them all individually which normally happens when we parse /etc/hosts into
// AuthHash where we add the "new" entries and discard (free) the already added
// entries. If we allocate as chunks, we can't free them individually.
- AuthEntity *storage = mDNSPlatformMemAllocate(sizeof(AuthEntity));
+ AuthEntity *storage = (AuthEntity *) mDNSPlatformMemAllocateClear(sizeof(*storage));
storage->next = mDNSNULL;
r->rrauth_free = storage;
}
@@ -314,7 +401,7 @@ mDNSlocal AuthGroup *GetAuthGroup(AuthHash *r, const ResourceRecord *const rr)
ag->rrauth_tail = &ag->members;
ag->NewLocalOnlyRecords = mDNSNULL;
if (namelen > sizeof(ag->namestorage))
- ag->name = mDNSPlatformMemAllocate(namelen);
+ ag->name = (domainname *) mDNSPlatformMemAllocate(namelen);
else
ag->name = (domainname*)ag->namestorage;
if (!ag->name)
@@ -452,14 +539,17 @@ mDNSexport char *InterfaceNameForID(mDNS *const m, const mDNSInterfaceID Interfa
}
// Caller should hold the lock
-mDNSlocal void GenerateNegativeResponse(mDNS *const m, mDNSInterfaceID InterfaceID, QC_result qc)
+mDNSlocal void GenerateNegativeResponseEx(mDNS *const m, mDNSInterfaceID InterfaceID, QC_result qc, mDNSBool noData)
{
DNSQuestion *q;
if (!m->CurrentQuestion) { LogMsg("GenerateNegativeResponse: ERROR!! CurrentQuestion not set"); return; }
q = m->CurrentQuestion;
- LogInfo("GenerateNegativeResponse: Generating negative response for question %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d->Q%d] GenerateNegativeResponse: Generating negative response for question " PRI_DM_NAME " (" PUB_S ")",
+ q->request_id, mDNSVal16(q->TargetQID), DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype));
MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, InterfaceID, mDNSNULL);
+ m->rec.r.resrec.negativeRecordType = noData ? kNegativeRecordType_NoData : kNegativeRecordType_Unspecified;
// We need to force the response through in the following cases
//
@@ -473,21 +563,24 @@ mDNSlocal void GenerateNegativeResponse(mDNS *const m, mDNSInterfaceID Interface
// Don't touch the question after this
m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
}
+#define GenerateNegativeResponse(M, INTERFACE_ID, QC) GenerateNegativeResponseEx(M, INTERFACE_ID, QC, mDNSfalse)
mDNSexport void AnswerQuestionByFollowingCNAME(mDNS *const m, DNSQuestion *q, ResourceRecord *rr)
{
const mDNSBool selfref = SameDomainName(&q->qname, &rr->rdata->u.name);
if (q->CNAMEReferrals >= 10 || selfref)
{
- LogMsg("AnswerQuestionByFollowingCNAME: %p %##s (%s) NOT following CNAME referral %d%s for %s",
- q, q->qname.c, DNSTypeName(q->qtype), q->CNAMEReferrals, selfref ? " (Self-Referential)" : "", RRDisplayString(m, rr));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d->Q%d] AnswerQuestionByFollowingCNAME: %p " PRI_DM_NAME " (" PUB_S ") NOT following CNAME referral %d" PUB_S " for " PRI_S,
+ q->request_id, mDNSVal16(q->TargetQID), q, DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype),
+ q->CNAMEReferrals, selfref ? " (Self-Referential)" : "", RRDisplayString(m, rr));
+
}
else
{
- const mDNSu32 c = q->CNAMEReferrals + 1; // Stash a copy of the new q->CNAMEReferrals value
UDPSocket *sock = q->LocalSocket;
mDNSOpaque16 id = q->TargetQID;
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
uDNSMetrics metrics;
#endif
@@ -508,10 +601,19 @@ mDNSexport void AnswerQuestionByFollowingCNAME(mDNS *const m, DNSQuestion *q, Re
// which we would subsequently cancel and retract if the CNAME referral record were removed.
// In reality this is such a corner case we'll ignore it until someone actually needs it.
- LogInfo("AnswerQuestionByFollowingCNAME: %p %##s (%s) following CNAME referral %d for %s",
- q, q->qname.c, DNSTypeName(q->qtype), q->CNAMEReferrals, RRDisplayString(m, rr));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d->Q%d] AnswerQuestionByFollowingCNAME: %p " PRI_DM_NAME " (" PUB_S ") following CNAME referral %d for " PRI_S,
+ q->request_id, mDNSVal16(q->TargetQID), q, DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype),
+ q->CNAMEReferrals, RRDisplayString(m, rr));
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ if (!mDNSOpaque16IsZero(q->TargetQID))
+ {
+ // Must be called before zeroing out q->metrics below.
+ Querier_PrepareQuestionForCNAMERestart(q);
+ }
+#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
if ((q->CNAMEReferrals == 0) && !q->metrics.originalQName)
{
domainname * qName;
@@ -520,7 +622,7 @@ mDNSexport void AnswerQuestionByFollowingCNAME(mDNS *const m, DNSQuestion *q, Re
qNameLen = DomainNameLength(&q->qname);
if ((qNameLen > 0) && (qNameLen <= MAX_DOMAIN_NAME))
{
- qName = mDNSPlatformMemAllocate(qNameLen);
+ qName = (domainname *) mDNSPlatformMemAllocate(qNameLen);
if (qName)
{
mDNSPlatformMemCopy(qName->c, q->qname.c, qNameLen);
@@ -529,6 +631,8 @@ mDNSexport void AnswerQuestionByFollowingCNAME(mDNS *const m, DNSQuestion *q, Re
}
}
metrics = q->metrics;
+ // The metrics will be transplanted to the restarted question, so zero out the old copy instead of using
+ // uDNSMetricsClear(), which will free any pointers to allocated memory.
mDNSPlatformMemZero(&q->metrics, sizeof(q->metrics));
#endif
mDNS_StopQuery_internal(m, q); // Stop old query
@@ -539,16 +643,20 @@ mDNSexport void AnswerQuestionByFollowingCNAME(mDNS *const m, DNSQuestion *q, Re
// to try this as unicast query even though it is a .local name
if (!mDNSOpaque16IsZero(q->TargetQID) && IsLocalDomain(&q->qname))
{
- LogInfo("AnswerQuestionByFollowingCNAME: Resolving a .local CNAME %p %##s (%s) Record %s",
- q, q->qname.c, DNSTypeName(q->qtype), RRDisplayString(m, rr));
- q->InterfaceID = mDNSInterface_Unicast;
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d->Q%d] AnswerQuestionByFollowingCNAME: Resolving a .local CNAME %p " PRI_DM_NAME " (" PUB_S ") Record " PRI_S,
+ q->request_id, mDNSVal16(q->TargetQID), q, DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype), RRDisplayString(m, rr));
+ q->IsUnicastDotLocal = mDNStrue;
}
+ q->CNAMEReferrals += 1; // Increment value before calling mDNS_StartQuery_internal
+ const mDNSu32 c = q->CNAMEReferrals; // Stash a copy of the new q->CNAMEReferrals value
mDNS_StartQuery_internal(m, q); // start new query
// Record how many times we've done this. We need to do this *after* mDNS_StartQuery_internal,
// because mDNS_StartQuery_internal re-initializes CNAMEReferrals to zero
q->CNAMEReferrals = c;
-#if AWD_METRICS
- metrics.expiredAnswerState = q->metrics.expiredAnswerState; // We want the newly initialized state for this value
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
+ metrics.expiredAnswerState = q->metrics.expiredAnswerState; // We want the newly initialized state for this value
+ metrics.dnsOverTCPState = q->metrics.dnsOverTCPState; // We want the newly initialized state for this value
q->metrics = metrics;
#endif
if (sock)
@@ -577,7 +685,7 @@ mDNSlocal mDNSu8 *PunycodeConvert(const mDNSu8 *const src, mDNSu8 *const dst, co
UErrorCode errorCode = U_ZERO_ERROR;
UIDNAInfo info = UIDNA_INFO_INITIALIZER;
UIDNA *uts46 = uidna_openUTS46(UIDNA_USE_STD3_RULES|UIDNA_NONTRANSITIONAL_TO_UNICODE, &errorCode);
- int32_t len = uidna_nameToASCII_UTF8(uts46, (const char *)src+1, src[0], (char *)dst+1, end-(dst+1), &info, &errorCode);
+ int32_t len = uidna_nameToASCII_UTF8(uts46, (const char *)src+1, src[0], (char *)dst+1, (int32_t)(end-(dst+1)), &info, &errorCode);
uidna_close(uts46);
#if DEBUG_PUNYCODE
if (errorCode) LogMsg("uidna_nameToASCII_UTF8(%##s) failed errorCode %d", src, errorCode);
@@ -628,7 +736,7 @@ mDNSlocal mDNSBool PerformNextPunycodeConversion(const DNSQuestion *const q, dom
const mDNSu8 remainder = DomainNameLength((domainname*)src);
if (dst + remainder > newname->c + MAX_DOMAIN_NAME) return mDNSfalse; // Name too long -- cannot be converted to Punycode
- mDNSPlatformMemCopy(newname->c, q->qname.c, h - q->qname.c); // Fill in the leading part
+ mDNSPlatformMemCopy(newname->c, q->qname.c, (mDNSu32)(h - q->qname.c)); // Fill in the leading part
mDNSPlatformMemCopy(dst, src, remainder); // Fill in the trailing part
#if DEBUG_PUNYCODE
LogMsg("PerformNextPunycodeConversion: %##s converted to %##s", q->qname.c, newname->c);
@@ -692,7 +800,7 @@ mDNSlocal void AnswerLocalQuestionWithLocalAuthRecord(mDNS *const m, AuthRecord
mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
}
-mDNSlocal void AnswerInterfaceAnyQuestionsWithLocalAuthRecord(mDNS *const m, AuthRecord *rr, QC_result AddRecord)
+mDNSlocal void AnswerInterfaceAnyQuestionsWithLocalAuthRecord(mDNS *const m, AuthRecord *ar, QC_result AddRecord)
{
if (m->CurrentQuestion)
LogMsg("AnswerInterfaceAnyQuestionsWithLocalAuthRecord: ERROR m->CurrentQuestion already set: %##s (%s)",
@@ -702,12 +810,12 @@ mDNSlocal void AnswerInterfaceAnyQuestionsWithLocalAuthRecord(mDNS *const m, Aut
{
mDNSBool answered;
DNSQuestion *q = m->CurrentQuestion;
- if (RRAny(rr))
- answered = ResourceRecordAnswersQuestion(&rr->resrec, q);
+ if (RRAny(ar))
+ answered = AuthRecordAnswersQuestion(ar, q);
else
- answered = LocalOnlyRecordAnswersQuestion(rr, q);
+ answered = LocalOnlyRecordAnswersQuestion(ar, q);
if (answered)
- AnswerLocalQuestionWithLocalAuthRecord(m, rr, AddRecord); // MUST NOT dereference q again
+ AnswerLocalQuestionWithLocalAuthRecord(m, ar, AddRecord); // MUST NOT dereference q again
if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
m->CurrentQuestion = q->next;
}
@@ -725,7 +833,7 @@ mDNSlocal void AnswerInterfaceAnyQuestionsWithLocalAuthRecord(mDNS *const m, Aut
// AnswerAllLocalQuestionsWithLocalAuthRecord is used by the m->NewLocalRecords loop in mDNS_Execute(),
// and by mDNS_Deregister_internal()
-mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRecord *rr, QC_result AddRecord)
+mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRecord *ar, QC_result AddRecord)
{
if (m->CurrentQuestion)
LogMsg("AnswerAllLocalQuestionsWithLocalAuthRecord ERROR m->CurrentQuestion already set: %##s (%s)",
@@ -737,12 +845,12 @@ mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRec
mDNSBool answered;
DNSQuestion *q = m->CurrentQuestion;
// We are called with both LocalOnly/P2P record or a regular AuthRecord
- if (RRAny(rr))
- answered = ResourceRecordAnswersQuestion(&rr->resrec, q);
+ if (RRAny(ar))
+ answered = AuthRecordAnswersQuestion(ar, q);
else
- answered = LocalOnlyRecordAnswersQuestion(rr, q);
+ answered = LocalOnlyRecordAnswersQuestion(ar, q);
if (answered)
- AnswerLocalQuestionWithLocalAuthRecord(m, rr, AddRecord); // MUST NOT dereference q again
+ AnswerLocalQuestionWithLocalAuthRecord(m, ar, AddRecord); // MUST NOT dereference q again
if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
m->CurrentQuestion = q->next;
}
@@ -750,8 +858,8 @@ mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRec
m->CurrentQuestion = mDNSNULL;
// If this AuthRecord is marked LocalOnly or P2P, then we want to deliver it to all local 'mDNSInterface_Any' questions
- if (rr->ARType == AuthRecordLocalOnly || rr->ARType == AuthRecordP2P)
- AnswerInterfaceAnyQuestionsWithLocalAuthRecord(m, rr, AddRecord);
+ if (ar->ARType == AuthRecordLocalOnly || ar->ARType == AuthRecordP2P)
+ AnswerInterfaceAnyQuestionsWithLocalAuthRecord(m, ar, AddRecord);
}
@@ -763,18 +871,45 @@ mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRec
#define RRTypeIsAddressType(T) ((T) == kDNSType_A || (T) == kDNSType_AAAA)
-#define ResourceRecordIsValidAnswer(RR) ( ((RR)->resrec.RecordType & kDNSRecordTypeActiveMask) && \
- ((RR)->Additional1 == mDNSNULL || ((RR)->Additional1->resrec.RecordType & kDNSRecordTypeActiveMask)) && \
- ((RR)->Additional2 == mDNSNULL || ((RR)->Additional2->resrec.RecordType & kDNSRecordTypeActiveMask)) && \
- ((RR)->DependentOn == mDNSNULL || ((RR)->DependentOn->resrec.RecordType & kDNSRecordTypeActiveMask)) )
+mDNSlocal mDNSBool ResourceRecordIsValidAnswer(const AuthRecord *const rr)
+{
+ if ((rr->resrec.RecordType & kDNSRecordTypeActiveMask) &&
+ ((rr->Additional1 == mDNSNULL) || (rr->Additional1->resrec.RecordType & kDNSRecordTypeActiveMask)) &&
+ ((rr->Additional2 == mDNSNULL) || (rr->Additional2->resrec.RecordType & kDNSRecordTypeActiveMask)) &&
+ ((rr->DependentOn == mDNSNULL) || (rr->DependentOn->resrec.RecordType & kDNSRecordTypeActiveMask)))
+ {
+ return mDNStrue;
+ }
+ else
+ {
+ return mDNSfalse;
+ }
+}
+
+mDNSlocal mDNSBool IsInterfaceValidForAuthRecord(const AuthRecord *const rr, const mDNSInterfaceID InterfaceID)
+{
+ if (rr->resrec.InterfaceID == mDNSInterface_Any)
+ {
+ return mDNSPlatformValidRecordForInterface(rr, InterfaceID);
+ }
+ else
+ {
+ return ((rr->resrec.InterfaceID == InterfaceID) ? mDNStrue : mDNSfalse);
+ }
+}
-#define ResourceRecordIsValidInterfaceAnswer(RR, INTID) \
- (ResourceRecordIsValidAnswer(RR) && \
- ((RR)->resrec.InterfaceID == mDNSInterface_Any || (RR)->resrec.InterfaceID == (INTID)))
+mDNSlocal mDNSBool ResourceRecordIsValidInterfaceAnswer(const AuthRecord *const rr, const mDNSInterfaceID interfaceID)
+{
+ return ((IsInterfaceValidForAuthRecord(rr, interfaceID) && ResourceRecordIsValidAnswer(rr)) ? mDNStrue : mDNSfalse);
+}
#define DefaultProbeCountForTypeUnique ((mDNSu8)3)
#define DefaultProbeCountForRecordType(X) ((X) == kDNSRecordTypeUnique ? DefaultProbeCountForTypeUnique : (mDNSu8)0)
+// Parameters for handling probing conflicts
+#define kMaxAllowedMCastProbingConflicts 1 // Maximum number of conflicts to allow from mcast messages.
+#define kProbingConflictPauseDuration mDNSPlatformOneSecond // Duration of probing pause after an allowed mcast conflict.
+
// See RFC 6762: "8.3 Announcing"
// "The Multicast DNS responder MUST send at least two unsolicited responses, one second apart."
// Send 4, which is really 8 since we send on both IPv4 and IPv6.
@@ -812,7 +947,7 @@ mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRec
// If we do our normal refresh at 80% of the TTL, our local caching server will return 20 seconds, so we'll do another
// 80% refresh after 16 seconds, and then the server will return 4 seconds, and so on, in the fashion of Zeno's paradox.
// To avoid this, we extend the record's effective TTL to give it a little extra grace period.
-// We adjust the 100 second TTL to 127. This means that when we do our 80% query at 102 seconds,
+// We adjust the 100 second TTL to 127. This means that when we do our 80% query after 102 seconds,
// the cached copy at our local caching server will already have expired, so the server will be forced
// to fetch a fresh copy from the authoritative server, and then return a fresh record with the full TTL of 3600 seconds.
@@ -937,6 +1072,7 @@ mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr)
if (rr->ProbeCount)
{
+ rr->ProbingConflictCount = 0;
// If we have no probe suppression time set, or it is in the past, set it now
if (m->SuppressProbes == 0 || m->SuppressProbes - m->timenow < 0)
{
@@ -1007,11 +1143,7 @@ mDNSlocal const domainname *SetUnicastTargetToHostName(mDNS *const m, AuthRecord
const domainname *target;
if (rr->AutoTarget)
{
- // For autotunnel services pointing at our IPv6 ULA we don't need or want a NAT mapping, but for all other
- // advertised services referencing our uDNS hostname, we want NAT mappings automatically created as appropriate,
- // with the port number in our advertised SRV record automatically tracking the external mapped port.
- DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, rr->resrec.name);
- if (!AuthInfo || !AuthInfo->AutoTunnel) rr->AutoTarget = Target_AutoHostAndNATMAP;
+ rr->AutoTarget = Target_AutoHostAndNATMAP;
}
target = GetServiceTarget(m, rr);
@@ -1029,13 +1161,30 @@ mDNSlocal const domainname *SetUnicastTargetToHostName(mDNS *const m, AuthRecord
}
}
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+mDNSlocal mDNSBool AuthRecordIncludesOrIsAWDL(const AuthRecord *const ar)
+{
+ return ((AuthRecordIncludesAWDL(ar) || mDNSPlatformInterfaceIsAWDL(ar->resrec.InterfaceID)) ? mDNStrue : mDNSfalse);
+}
+#endif
+
// Right now this only applies to mDNS (.local) services where the target host is always m->MulticastHostname
// Eventually we should unify this with GetServiceTarget() in uDNS.c
mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr)
{
domainname *const target = GetRRDomainNameTarget(&rr->resrec);
- const domainname *newname = &m->MulticastHostname;
+ const domainname *newname;
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ if (AuthRecordIncludesOrIsAWDL(rr))
+ {
+ newname = &m->RandomizedHostname;
+ }
+ else
+#endif
+ {
+ newname = &m->MulticastHostname;
+ }
if (!target) LogInfo("SetTargetToHostName: Don't know how to set the target of rrtype %s", DNSTypeName(rr->resrec.rrtype));
if (!(rr->ForceMCast || rr->ARType == AuthRecordLocalOnly || rr->ARType == AuthRecordP2P || IsLocalDomain(&rr->namestorage)))
@@ -1133,16 +1282,18 @@ mDNSexport void ActivateUnicastRegistration(mDNS *const m, AuthRecord *const rr)
LogInfo("ActivateUnicastRegistration: Resource record %s, current state %d, moving to Pending", ARDisplayString(m, rr), rr->state);
rr->state = regState_Pending;
}
- rr->ProbeCount = 0;
- rr->ProbeRestartCount = 0;
- rr->AnnounceCount = 0;
- rr->ThisAPInterval = INIT_RECORD_REG_INTERVAL;
- rr->LastAPTime = m->timenow - rr->ThisAPInterval;
- rr->expire = 0; // Forget about all the leases, start fresh
- rr->uselease = mDNStrue;
- rr->updateid = zeroID;
- rr->SRVChanged = mDNSfalse;
- rr->updateError = mStatus_NoError;
+ rr->ProbingConflictCount = 0;
+ rr->LastConflictPktNum = 0;
+ rr->ProbeRestartCount = 0;
+ rr->ProbeCount = 0;
+ rr->AnnounceCount = 0;
+ rr->ThisAPInterval = INIT_RECORD_REG_INTERVAL;
+ rr->LastAPTime = m->timenow - rr->ThisAPInterval;
+ rr->expire = 0; // Forget about all the leases, start fresh
+ rr->uselease = mDNStrue;
+ rr->updateid = zeroID;
+ rr->SRVChanged = mDNSfalse;
+ rr->updateError = mStatus_NoError;
// RestartRecordGetZoneData calls this function whenever a new interface gets registered with core.
// The records might already be registered with the server and hence could have NAT state.
if (rr->NATinfo.clientContext)
@@ -1233,7 +1384,6 @@ mDNSlocal AuthRecord *CheckAuthSameRecord(AuthHash *r, AuthRecord *rr)
return (mDNSNULL);
}
-
mDNSlocal void DecrementAutoTargetServices(mDNS *const m, AuthRecord *const rr)
{
if (RRLocalOnly(rr))
@@ -1243,31 +1393,99 @@ mDNSlocal void DecrementAutoTargetServices(mDNS *const m, AuthRecord *const rr)
return;
}
- if (!AuthRecord_uDNS(rr) && rr->resrec.rrtype == kDNSType_SRV && rr->AutoTarget == Target_AutoHost)
+ if (!AuthRecord_uDNS(rr) && (rr->resrec.rrtype == kDNSType_SRV) && (rr->AutoTarget == Target_AutoHost))
{
- // If about to get rid of the last advertised service
- if (m->AutoTargetServices == 1)
- DeadvertiseAllInterfaceRecords(m);
-
- m->AutoTargetServices--;
- LogInfo("DecrementAutoTargetServices: AutoTargetServices %d Record %s", m->AutoTargetServices, ARDisplayString(m, rr));
+ NetworkInterfaceInfo *intf;
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ DeadvertiseFlags flags = 0; // DeadvertiseFlags for non-AWDL interfaces.
+ DeadvertiseFlags flagsAWDL = 0; // DeadvertiseFlags for AWDL interfaces.
+ if (AuthRecordIncludesOrIsAWDL(rr))
+ {
+ if (AuthRecordIncludesAWDL(rr))
+ {
+ m->AutoTargetAWDLIncludedCount--;
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "DecrementAutoTargetServices: AutoTargetAWDLIncludedCount %u Record " PRI_S,
+ m->AutoTargetAWDLIncludedCount, ARDisplayString(m, rr));
+ if (m->AutoTargetAWDLIncludedCount == 0)
+ {
+ flags |= kDeadvertiseFlag_RandHostname;
+ if (m->AutoTargetAWDLOnlyCount == 0) flagsAWDL |= kDeadvertiseFlag_RandHostname;
+ }
+ }
+ else
+ {
+ m->AutoTargetAWDLOnlyCount--;
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "DecrementAutoTargetServices: AutoTargetAWDLOnlyCount %u Record " PRI_S,
+ m->AutoTargetAWDLOnlyCount, ARDisplayString(m, rr));
+ if ((m->AutoTargetAWDLIncludedCount == 0) && (m->AutoTargetAWDLOnlyCount == 0))
+ {
+ flagsAWDL |= kDeadvertiseFlag_RandHostname;
+ }
+ }
+ if (flags || flagsAWDL)
+ {
+ for (intf = m->HostInterfaces; intf; intf = intf->next)
+ {
+ if (!intf->Advertise) continue;
+ if (mDNSPlatformInterfaceIsAWDL(intf->InterfaceID))
+ {
+ if (flagsAWDL) DeadvertiseInterface(m, intf, flagsAWDL);
+ }
+ else
+ {
+ if (flags) DeadvertiseInterface(m, intf, flags);
+ }
+ }
+ }
+ if ((m->AutoTargetAWDLIncludedCount == 0) && (m->AutoTargetAWDLOnlyCount == 0))
+ {
+ GetRandomUUIDLocalHostname(&m->RandomizedHostname);
+ }
+ }
+ else
+#endif
+ {
+ m->AutoTargetServices--;
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "DecrementAutoTargetServices: AutoTargetServices %u Record " PRI_S,
+ m->AutoTargetServices, ARDisplayString(m, rr));
+ if (m->AutoTargetServices == 0)
+ {
+ for (intf = m->HostInterfaces; intf; intf = intf->next)
+ {
+ if (intf->Advertise) DeadvertiseInterface(m, intf, kDeadvertiseFlag_NormalHostname);
+ }
+ }
+ }
}
-#if BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
if (!AuthRecord_uDNS(rr))
{
if (m->NumAllInterfaceRecords + m->NumAllInterfaceQuestions == 1)
m->NextBonjourDisableTime = NonZeroTime(m->timenow + (BONJOUR_DISABLE_DELAY * mDNSPlatformOneSecond));
m->NumAllInterfaceRecords--;
- LogInfo("DecrementAutoTargetServices: NumAllInterfaceRecords %d NumAllInterfaceQuestions %d %s",
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "DecrementAutoTargetServices: NumAllInterfaceRecords %u NumAllInterfaceQuestions %u " PRI_S,
m->NumAllInterfaceRecords, m->NumAllInterfaceQuestions, ARDisplayString(m, rr));
}
-#endif // BONJOUR_ON_DEMAND
+#endif
+}
+
+mDNSlocal void AdvertiseNecessaryInterfaceRecords(mDNS *const m)
+{
+ NetworkInterfaceInfo *intf;
+ for (intf = m->HostInterfaces; intf; intf = intf->next)
+ {
+ if (intf->Advertise) AdvertiseInterfaceIfNeeded(m, intf);
+ }
}
mDNSlocal void IncrementAutoTargetServices(mDNS *const m, AuthRecord *const rr)
{
- mDNSBool enablingBonjour = 0;
+ mDNSBool enablingBonjour = mDNSfalse;
if (RRLocalOnly(rr))
{
@@ -1276,11 +1494,12 @@ mDNSlocal void IncrementAutoTargetServices(mDNS *const m, AuthRecord *const rr)
return;
}
-#if BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
if (!AuthRecord_uDNS(rr))
{
m->NumAllInterfaceRecords++;
- LogInfo("IncrementAutoTargetServices: NumAllInterfaceRecords %d NumAllInterfaceQuestions %d %s",
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "IncrementAutoTargetServices: NumAllInterfaceRecords %u NumAllInterfaceQuestions %u " PRI_S,
m->NumAllInterfaceRecords, m->NumAllInterfaceQuestions, ARDisplayString(m, rr));
if (m->NumAllInterfaceRecords + m->NumAllInterfaceQuestions == 1)
{
@@ -1290,24 +1509,43 @@ mDNSlocal void IncrementAutoTargetServices(mDNS *const m, AuthRecord *const rr)
// Enable Bonjour immediately by scheduling network changed processing where
// we will join the multicast group on each active interface.
m->BonjourEnabled = 1;
- enablingBonjour = 1;
+ enablingBonjour = mDNStrue;
m->NetworkChanged = m->timenow;
}
}
}
-#endif // BONJOUR_ON_DEMAND
+#endif
- if (!AuthRecord_uDNS(rr) && rr->resrec.rrtype == kDNSType_SRV && rr->AutoTarget == Target_AutoHost)
+ if (!AuthRecord_uDNS(rr) && (rr->resrec.rrtype == kDNSType_SRV) && (rr->AutoTarget == Target_AutoHost))
{
- m->AutoTargetServices++;
- LogInfo("IncrementAutoTargetServices: AutoTargetServices %d Record %s", m->AutoTargetServices, ARDisplayString(m, rr));
-
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ if (AuthRecordIncludesAWDL(rr))
+ {
+ m->AutoTargetAWDLIncludedCount++;
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "IncrementAutoTargetServices: AutoTargetAWDLIncludedCount %u Record " PRI_S,
+ m->AutoTargetAWDLIncludedCount, ARDisplayString(m, rr));
+ }
+ else if (mDNSPlatformInterfaceIsAWDL(rr->resrec.InterfaceID))
+ {
+ m->AutoTargetAWDLOnlyCount++;
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "IncrementAutoTargetServices: AutoTargetAWDLOnlyCount %u Record " PRI_S,
+ m->AutoTargetAWDLOnlyCount, ARDisplayString(m, rr));
+ }
+ else
+#endif
+ {
+ m->AutoTargetServices++;
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "IncrementAutoTargetServices: AutoTargetServices %u Record " PRI_S,
+ m->AutoTargetServices, ARDisplayString(m, rr));
+ }
// If this is the first advertised service and we did not just enable Bonjour above, then
// advertise all the interface records. If we did enable Bonjour above, the interface records will
// be advertised during the network changed processing scheduled above, so no need
// to do it here.
- if ((m->AutoTargetServices == 1) && (enablingBonjour == 0))
- AdvertiseAllInterfaceRecords(m);
+ if (!enablingBonjour) AdvertiseNecessaryInterfaceRecords(m);
}
}
@@ -1553,7 +1791,6 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
if (!m->NewLocalRecords) m->NewLocalRecords = rr;
// When we called SetTargetToHostName, it may have caused mDNS_Register_internal to be re-entered, appending new
// records to the list, so we now need to update p to advance to the new end to the list before appending our new record.
- // Note that for AutoTunnel this should never happen, but this check makes the code future-proof.
while (*p) p=&(*p)->next;
*p = rr;
if (rr->resrec.RecordType == kDNSRecordTypeUnique) rr->resrec.RecordType = kDNSRecordTypeVerified;
@@ -1792,7 +2029,7 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
// we need to retract that announcement before we delete the record
// If this is a record (including mDNSInterface_LocalOnly records) for which we've given local-only answers then
- // it's tempting to just do "AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse)" here, but that would not not be safe.
+ // it's tempting to just do "AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, QC_rmv)" here, but that would not not be safe.
// The AnswerAllLocalQuestionsWithLocalAuthRecord routine walks the question list invoking client callbacks, using the "m->CurrentQuestion"
// mechanism to cope with the client callback modifying the question list while that's happening.
// However, mDNS_Deregister could have been called from a client callback (e.g. from the domain enumeration callback FoundDomain)
@@ -1819,7 +2056,7 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
}
// Sometimes the records don't complete proper deregistration i.e., don't wait for a response
// from the server. In that case, if the records have been part of a group update, clear the
- // state here. Some recors e.g., AutoTunnel gets reused without ever being completely initialized
+ // state here.
rr->updateid = zeroID;
// We defer cleaning up NAT state only after sending goodbyes. This is important because
@@ -1847,14 +2084,9 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
return(mStatus_BadReferenceErr);
}
- // <rdar://problem/7457925> Local-only questions don't get remove events for unique records
- // We may want to consider changing this code so that we generate local-only question "rmv"
- // events (and maybe goodbye packets too) for unique records as well as for shared records
- // Note: If we change the logic for this "if" statement, need to ensure that the code in
- // CompleteDeregistration() sets the appropriate state variables to gaurantee that "else"
- // clause will execute here and the record will be cut from the list.
if (rr->WakeUp.HMAC.l[0] ||
- (RecordType == kDNSRecordTypeShared && (rr->RequireGoodbye || rr->AnsweredLocalQ)))
+ (((RecordType == kDNSRecordTypeShared) || (rr->ARType == AuthRecordLocalOnly)) &&
+ (rr->RequireGoodbye || rr->AnsweredLocalQ)))
{
verbosedebugf("mDNS_Deregister_internal: Starting deregistration for %s", ARDisplayString(m, rr));
rr->resrec.RecordType = kDNSRecordTypeDeregistering;
@@ -1883,10 +2115,6 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
if (m->CurrentRecord == rr) m->CurrentRecord = rr->next;
rr->next = mDNSNULL;
- // Should we generate local remove events here?
- // i.e. something like:
- // if (rr->AnsweredLocalQ) { AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse); rr->AnsweredLocalQ = mDNSfalse; }
-
verbosedebugf("mDNS_Deregister_internal: Deleting record for %s", ARDisplayString(m, rr));
rr->resrec.RecordType = kDNSRecordTypeUnregistered;
@@ -1929,7 +2157,7 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
}
else
{
-#if APPLE_OSX_mDNSResponder
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
// See if this record was also registered with any D2D plugins.
D2D_stop_advertising_record(r2);
#endif
@@ -2034,21 +2262,12 @@ mDNSlocal void AddAdditionalsToResponseList(mDNS *const m, AuthRecord *ResponseR
}
}
-mDNSlocal int AnonInfoSpace(AnonymousInfo *info)
-{
- ResourceRecord *rr = info->nsec3RR;
-
- // 2 bytes for compressed name + type (2) class (2) TTL (4) rdlength (2) rdata (n)
- return (2 + 10 + rr->rdlength);
-}
-
mDNSlocal void SendDelayedUnicastResponse(mDNS *const m, const mDNSAddr *const dest, const mDNSInterfaceID InterfaceID)
{
AuthRecord *rr;
AuthRecord *ResponseRecords = mDNSNULL;
AuthRecord **nrp = &ResponseRecords;
NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID);
- int AnoninfoSpace = 0;
// Make a list of all our records that need to be unicast to this destination
for (rr = m->ResourceRecords; rr; rr=rr->next)
@@ -2097,17 +2316,10 @@ mDNSlocal void SendDelayedUnicastResponse(mDNS *const m, const mDNSAddr *const d
while (ResponseRecords && ResponseRecords->NR_AnswerTo)
{
rr = ResponseRecords;
- if (rr->resrec.AnonInfo)
- {
- AnoninfoSpace += AnonInfoSpace(rr->resrec.AnonInfo);
- rr->resrec.AnonInfo->SendNow = mDNSInterfaceMark;
- }
if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it
- // Retract the limit by AnoninfoSpace which we need to put the AnoInfo option.
- newptr = PutResourceRecordTTLWithLimit(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, rr->resrec.rroriginalttl,
- m->omsg.data + (AllowedRRSpace(&m->omsg) - AnoninfoSpace));
+ newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec);
rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state
if (!newptr && m->omsg.h.numAnswers)
@@ -2122,29 +2334,6 @@ mDNSlocal void SendDelayedUnicastResponse(mDNS *const m, const mDNSAddr *const d
rr->RequireGoodbye = mDNStrue;
}
- // We have reserved the space for AnonInfo option. PutResourceRecord uses the
- // standard limit (AllowedRRSpace) and we should have space now.
- for (rr = m->ResourceRecords; rr; rr=rr->next)
- {
- if (rr->resrec.AnonInfo && rr->resrec.AnonInfo->SendNow == mDNSInterfaceMark)
- {
- ResourceRecord *nsec3RR = rr->resrec.AnonInfo->nsec3RR;
-
- newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAuthorities, nsec3RR);
- if (newptr)
- {
- responseptr = newptr;
- debugf("SendDelayedUnicastResponse: Added NSEC3 Record %s on %p", RRDisplayString(m, nsec3RR), intf->InterfaceID);
- }
- else
- {
- // We allocated space and we should not fail. Don't break, we need to clear the SendNow flag.
- LogMsg("SendDelayedUnicastResponse: ERROR!! Cannot Add NSEC3 Record %s on %p", RRDisplayString(m, nsec3RR), intf->InterfaceID);
- }
- rr->resrec.AnonInfo->SendNow = mDNSNULL;
- }
- }
-
// Add additionals, if there's space
while (ResponseRecords && !ResponseRecords->NR_AnswerTo)
{
@@ -2164,7 +2353,7 @@ mDNSlocal void SendDelayedUnicastResponse(mDNS *const m, const mDNSAddr *const d
}
if (m->omsg.h.numAnswers)
- mDNSSendDNSMessage(m, &m->omsg, responseptr, InterfaceID, mDNSNULL, dest, MulticastDNSPort, mDNSNULL, mDNSNULL, mDNSfalse);
+ mDNSSendDNSMessage(m, &m->omsg, responseptr, InterfaceID, mDNSNULL, mDNSNULL, dest, MulticastDNSPort, mDNSNULL, mDNSfalse);
}
}
@@ -2497,22 +2686,6 @@ mDNSlocal mDNSBool ShouldSendGoodbyesBeforeSleep(mDNS *const m, const NetworkInt
}
}
-mDNSlocal mDNSBool IsInterfaceValidForAuthRecord(const AuthRecord *ar, mDNSInterfaceID InterfaceID)
-{
- mDNSBool result;
-
- if (ar->resrec.InterfaceID == mDNSInterface_Any)
- {
- result = mDNSPlatformValidRecordForInterface(ar, InterfaceID);
- }
- else
- {
- result = (ar->resrec.InterfaceID == InterfaceID);
- }
-
- return(result);
-}
-
// Note about acceleration of announcements to facilitate automatic coalescing of
// multiple independent threads of announcements into a single synchronized thread:
// The announcements in the packet may be at different stages of maturity;
@@ -2745,7 +2918,6 @@ mDNSlocal void SendResponses(mDNS *const m)
int numDereg = 0;
int numAnnounce = 0;
int numAnswer = 0;
- int AnoninfoSpace = 0;
mDNSu8 *responseptr = m->omsg.data;
mDNSu8 *newptr;
InitializeDNSMessage(&m->omsg.h, zeroID, ResponseFlags);
@@ -2783,17 +2955,6 @@ mDNSlocal void SendResponses(mDNS *const m)
SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength);
}
- if (rr->resrec.AnonInfo)
- {
- int tmp = AnonInfoSpace(rr->resrec.AnonInfo);
-
- AnoninfoSpace += tmp;
- // Adjust OwnerRecordSpace/TraceRecordSpace which is used by PutRR_OS_TTL below so that
- // we have space to put in the NSEC3 record in the authority section.
- OwnerRecordSpace += tmp;
- TraceRecordSpace += tmp;
- }
-
if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it
newptr = PutRR_OS_TTL(responseptr, &m->omsg.h.numAnswers, &rr->resrec, active ? rr->resrec.rroriginalttl : 0);
@@ -2816,13 +2977,6 @@ mDNSlocal void SendResponses(mDNS *const m)
if (newptr) // If succeeded in sending, advance to next interface
{
- if (rr->resrec.AnonInfo)
- {
- debugf("SendResponses: Marking %s, OwnerRecordSpace %d, TraceRecordSpace %d, limit %p", ARDisplayString(m, rr), OwnerRecordSpace,
- TraceRecordSpace, m->omsg.data + AllowedRRSpace(&m->omsg) - OwnerRecordSpace - TraceRecordSpace);
- rr->resrec.AnonInfo->SendNow = intf->InterfaceID;
- }
-
// If sending on all interfaces, go to next interface; else we're finished now
if (rr->ImmedAnswer == mDNSInterfaceMark && rr->resrec.InterfaceID == mDNSInterface_Any)
rr->SendRNow = GetNextActiveInterfaceID(intf);
@@ -2832,31 +2986,6 @@ mDNSlocal void SendResponses(mDNS *const m)
}
}
- // Get the reserved space back
- OwnerRecordSpace -= AnoninfoSpace;
- TraceRecordSpace -= AnoninfoSpace;
- newptr = responseptr;
- for (rr = m->ResourceRecords; rr; rr=rr->next)
- {
- if (rr->resrec.AnonInfo && rr->resrec.AnonInfo->SendNow == intf->InterfaceID)
- {
- ResourceRecord *nsec3RR = rr->resrec.AnonInfo->nsec3RR;
-
- newptr = PutRR_OS_TTL(newptr, &m->omsg.h.numAuthorities, nsec3RR, nsec3RR->rroriginalttl);
- if (newptr)
- {
- responseptr = newptr;
- debugf("SendResponses: Added NSEC3 %s, OwnerRecordSpace %d, TraceRecordSpace %d, limit %p", ARDisplayString(m, rr), OwnerRecordSpace,
- TraceRecordSpace, m->omsg.data + AllowedRRSpace(&m->omsg) - OwnerRecordSpace - TraceRecordSpace);
- }
- else
- {
- LogMsg("SendResponses: Cannot add NSEC3 %s, OwnerRecordSpace %d, TraceRecordSpace %d, limit %p", ARDisplayString(m, rr), OwnerRecordSpace,
- TraceRecordSpace, m->omsg.data + AllowedRRSpace(&m->omsg) - OwnerRecordSpace - TraceRecordSpace);
- }
- rr->resrec.AnonInfo->SendNow = mDNSNULL;
- }
- }
// Second Pass. Add additional records, if there's space.
newptr = responseptr;
for (rr = m->ResourceRecords; rr; rr=rr->next)
@@ -3005,8 +3134,8 @@ mDNSlocal void SendResponses(mDNS *const m)
numAnswer, numAnswer == 1 ? "" : "s",
m->omsg.h.numAdditionals, m->omsg.h.numAdditionals == 1 ? "" : "s", intf->InterfaceID);
- if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, mDNSNULL, &AllDNSLinkGroup_v4, MulticastDNSPort, mDNSNULL, mDNSNULL, mDNSfalse);
- if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, mDNSNULL, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, mDNSNULL, mDNSfalse);
+ if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, mDNSNULL, mDNSNULL, &AllDNSLinkGroup_v4, MulticastDNSPort, mDNSNULL, mDNSfalse);
+ if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, mDNSNULL, mDNSNULL, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, mDNSfalse);
if (!m->SuppressSending) m->SuppressSending = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+9)/10);
if (++pktcount >= 1000) { LogMsg("SendResponses exceeded loop limit %d: giving up", pktcount); break; }
// There might be more things to send on this interface, so go around one more time and try again.
@@ -3039,7 +3168,7 @@ mDNSlocal void SendResponses(mDNS *const m)
{
if (rr->ARType != AuthRecordLocalOnly && rr->ARType != AuthRecordP2P)
LogInfo("SendResponses: No active interface %d to send: %d %02X %s",
- (uint32_t)rr->SendRNow, (uint32_t)rr->resrec.InterfaceID, rr->resrec.RecordType, ARDisplayString(m, rr));
+ IIDPrintable(rr->SendRNow), IIDPrintable(rr->resrec.InterfaceID), rr->resrec.RecordType, ARDisplayString(m, rr));
rr->SendRNow = mDNSNULL;
}
@@ -3076,13 +3205,13 @@ mDNSlocal void SendResponses(mDNS *const m)
// so allow at most 1/10 second lateness
// 5. For records with rroriginalttl set to zero, that means we really want to delete them immediately
// (we have a new record with DelayDelivery set, waiting for the old record to go away before we can notify clients).
-#define CacheCheckGracePeriod(RR) ( \
- ((RR)->CRActiveQuestion == mDNSNULL ) ? (60 * mDNSPlatformOneSecond) : \
- ((RR)->UnansweredQueries < MaxUnansweredQueries) ? (TicksTTL(rr)/50) : \
- ((RR)->resrec.rroriginalttl > 10 ) ? (mDNSPlatformOneSecond) : \
- ((RR)->resrec.rroriginalttl > 0 ) ? (mDNSPlatformOneSecond/10) : 0)
+#define CacheCheckGracePeriod(CR) ( \
+ ((CR)->CRActiveQuestion == mDNSNULL ) ? (60 * mDNSPlatformOneSecond) : \
+ ((CR)->UnansweredQueries < MaxUnansweredQueries) ? (TicksTTL(CR)/50) : \
+ ((CR)->resrec.rroriginalttl > 10 ) ? (mDNSPlatformOneSecond) : \
+ ((CR)->resrec.rroriginalttl > 0 ) ? (mDNSPlatformOneSecond/10) : 0)
-#define NextCacheCheckEvent(RR) ((RR)->NextRequiredQuery + CacheCheckGracePeriod(RR))
+#define NextCacheCheckEvent(CR) ((CR)->NextRequiredQuery + CacheCheckGracePeriod(CR))
mDNSexport void ScheduleNextCacheCheckTime(mDNS *const m, const mDNSu32 slot, const mDNSs32 event)
{
@@ -3156,8 +3285,7 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, const NetworkInterfaceInfo *intf
mDNSBool ucast = (q->LargeAnswers || q->RequestUnicast) && m->CanReceiveUnicastOn5353 && intf->SupportsUnicastMDNSResponse;
mDNSu16 ucbit = (mDNSu16)(ucast ? kDNSQClass_UnicastResponse : 0);
const mDNSu8 *const limit = query->data + NormalMaxDNSMessageData;
- mDNSu8 anoninfo_space = q->AnonInfo ? AnonInfoSpace(q->AnonInfo) : 0;
- mDNSu8 *newptr = putQuestion(query, *queryptr, limit - *answerforecast - anoninfo_space, &q->qname, q->qtype, (mDNSu16)(q->qclass | ucbit));
+ mDNSu8 *newptr = putQuestion(query, *queryptr, limit - *answerforecast, &q->qname, q->qtype, (mDNSu16)(q->qclass | ucbit));
if (!newptr)
{
debugf("BuildQuestion: No more space in this packet for question %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
@@ -3165,18 +3293,18 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, const NetworkInterfaceInfo *intf
}
else
{
- mDNSu32 forecast = *answerforecast + anoninfo_space;
+ mDNSu32 forecast = *answerforecast;
const CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname);
- CacheRecord *rr;
+ CacheRecord *cr;
CacheRecord **ka = *kalistptrptr; // Make a working copy of the pointer we're going to update
- for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) // If we have a resource record in our cache,
- if (rr->resrec.InterfaceID == q->SendQNow && // received on this interface
- !(rr->resrec.RecordType & kDNSRecordTypeUniqueMask) && // which is a shared (i.e. not unique) record type
- rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList && // which is not already in the known answer list
- rr->resrec.rdlength <= SmallRecordLimit && // which is small enough to sensibly fit in the packet
- SameNameRecordAnswersQuestion(&rr->resrec, q) && // which answers our question
- rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow > // and its half-way-to-expiry time is at least 1 second away
+ for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next) // If we have a resource record in our cache,
+ if (cr->resrec.InterfaceID == q->SendQNow && // received on this interface
+ !(cr->resrec.RecordType & kDNSRecordTypeUniqueMask) && // which is a shared (i.e. not unique) record type
+ cr->NextInKAList == mDNSNULL && ka != &cr->NextInKAList && // which is not already in the known answer list
+ cr->resrec.rdlength <= SmallRecordLimit && // which is small enough to sensibly fit in the packet
+ SameNameCacheRecordAnswersQuestion(cr, q) && // which answers our question
+ cr->TimeRcvd + TicksTTL(cr)/2 - m->timenow > // and its half-way-to-expiry time is at least 1 second away
mDNSPlatformOneSecond) // (also ensures we never include goodbye records with TTL=1)
{
// We don't want to include unique records in the Known Answer section. The Known Answer section
@@ -3185,10 +3313,10 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, const NetworkInterfaceInfo *intf
// which we have a unique record already in our cache, then including that unique record as a
// Known Answer, so as to suppress the only answer we were expecting to get, makes little sense.
- *ka = rr; // Link this record into our known answer chain
- ka = &rr->NextInKAList;
+ *ka = cr; // Link this record into our known answer chain
+ ka = &cr->NextInKAList;
// We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
- forecast += 12 + rr->resrec.rdestimate;
+ forecast += 12 + cr->resrec.rdestimate;
// If we're trying to put more than one question in this packet, and it doesn't fit
// then undo that last question and try again next time
if (query->h.numQuestions > 1 && newptr + forecast >= limit)
@@ -3208,14 +3336,14 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, const NetworkInterfaceInfo *intf
*kalistptrptr = ka; // Update the known answer list pointer
if (ucast) q->ExpectUnicastResp = NonZeroTime(m->timenow);
- for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) // For every resource record in our cache,
- if (rr->resrec.InterfaceID == q->SendQNow && // received on this interface
- rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList && // which is not in the known answer list
- SameNameRecordAnswersQuestion(&rr->resrec, q)) // which answers our question
+ for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next) // For every resource record in our cache,
+ if (cr->resrec.InterfaceID == q->SendQNow && // received on this interface
+ cr->NextInKAList == mDNSNULL && ka != &cr->NextInKAList && // which is not in the known answer list
+ SameNameCacheRecordAnswersQuestion(cr, q)) // which answers our question
{
- rr->UnansweredQueries++; // indicate that we're expecting a response
- rr->LastUnansweredTime = m->timenow;
- SetNextCacheCheckTimeForRecord(m, rr);
+ cr->UnansweredQueries++; // indicate that we're expecting a response
+ cr->LastUnansweredTime = m->timenow;
+ SetNextCacheCheckTimeForRecord(m, cr);
}
return(mDNStrue);
@@ -3279,7 +3407,7 @@ mDNSlocal const CacheRecord *FindSPSInCache1(mDNS *const m, const DNSQuestion *c
for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
if (cr->resrec.rrtype == kDNSType_PTR && cr->resrec.rdlength >= 6) // If record is PTR type, with long enough name,
if (cr != c0 && cr != c1) // that's not one we've seen before,
- if (SameNameRecordAnswersQuestion(&cr->resrec, q)) // and answers our browse query,
+ if (SameNameCacheRecordAnswersQuestion(cr, q)) // and answers our browse query,
if (!IdenticalSameNameRecord(&cr->resrec, &m->SPSRecords.RR_PTR.resrec)) // and is not our own advertised service...
{
mDNSu32 metric = SPSMetric(cr->resrec.rdata->u.name.c);
@@ -3446,15 +3574,15 @@ mDNSlocal mDNSBool AccelerateThisQuery(mDNS *const m, DNSQuestion *q)
// We forecast: qname (n) type (2) class (2)
mDNSu32 forecast = (mDNSu32)DomainNameLength(&q->qname) + 4;
const CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname);
- const CacheRecord *rr;
- for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) // If we have a resource record in our cache,
- if (rr->resrec.rdlength <= SmallRecordLimit && // which is small enough to sensibly fit in the packet
- SameNameRecordAnswersQuestion(&rr->resrec, q) && // which answers our question
- rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow >= 0 && // and it is less than half-way to expiry
- rr->NextRequiredQuery - (m->timenow + q->ThisQInterval) > 0) // and we'll ask at least once again before NextRequiredQuery
+ const CacheRecord *cr;
+ for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next) // If we have a resource record in our cache,
+ if (cr->resrec.rdlength <= SmallRecordLimit && // which is small enough to sensibly fit in the packet
+ SameNameCacheRecordAnswersQuestion(cr, q) && // which answers our question
+ cr->TimeRcvd + TicksTTL(cr)/2 - m->timenow >= 0 && // and it is less than half-way to expiry
+ cr->NextRequiredQuery - (m->timenow + q->ThisQInterval) > 0) // and we'll ask at least once again before NextRequiredQuery
{
// We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
- forecast += 12 + rr->resrec.rdestimate;
+ forecast += 12 + cr->resrec.rdestimate;
if (forecast >= 512) return(mDNSfalse); // If this would add 512 bytes or more to the packet, don't accelerate
}
return(mDNStrue);
@@ -3503,11 +3631,7 @@ mDNSlocal void SendQueries(mDNS *const m)
ExpireDupSuppressInfoOnInterface(q->DupSuppress, m->timenow - TicksTTL(cr)/20, cr->resrec.InterfaceID);
// For uDNS queries (TargetQID non-zero) we adjust LastQTime,
// and bump UnansweredQueries so that we don't spin trying to send the same cache expiration query repeatedly
- if (q->Target.type)
- {
- q->SendQNow = mDNSInterfaceMark; // If targeted query, mark it
- }
- else if (!mDNSOpaque16IsZero(q->TargetQID))
+ if (!mDNSOpaque16IsZero(q->TargetQID))
{
q->LastQTime = m->timenow - q->ThisQInterval;
cr->UnansweredQueries++;
@@ -3542,29 +3666,7 @@ mDNSlocal void SendQueries(mDNS *const m)
while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
{
q = m->CurrentQuestion;
- if (q->Target.type && (q->SendQNow || TimeToSendThisQuestion(q, m->timenow)))
- {
- mDNSu8 *qptr = m->omsg.data;
- const mDNSu8 *const limit = m->omsg.data + sizeof(m->omsg.data);
-
- // If we fail to get a new on-demand socket (should only happen cases of the most extreme resource exhaustion), we'll try again next time
- if (!q->LocalSocket) q->LocalSocket = mDNSPlatformUDPSocket(zeroIPPort);
- if (q->LocalSocket)
- {
- InitializeDNSMessage(&m->omsg.h, q->TargetQID, QueryFlags);
- qptr = putQuestion(&m->omsg, qptr, limit, &q->qname, q->qtype, q->qclass);
- mDNSSendDNSMessage(m, &m->omsg, qptr, mDNSInterface_Any, q->LocalSocket, &q->Target, q->TargetPort, mDNSNULL, mDNSNULL, q->UseBackgroundTrafficClass);
- q->ThisQInterval *= QuestionIntervalStep;
- }
- if (q->ThisQInterval > MaxQuestionInterval)
- q->ThisQInterval = MaxQuestionInterval;
- q->LastQTime = m->timenow;
- q->LastQTxTime = m->timenow;
- q->RecentAnswerPkts = 0;
- q->SendQNow = mDNSNULL;
- q->ExpectUnicastResp = NonZeroTime(m->timenow);
- }
- else if (mDNSOpaque16IsZero(q->TargetQID) && !q->Target.type && TimeToSendThisQuestion(q, m->timenow))
+ if (mDNSOpaque16IsZero(q->TargetQID) && TimeToSendThisQuestion(q, m->timenow))
{
//LogInfo("Time to send %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - NextQSendTime(q));
q->SendQNow = mDNSInterfaceMark; // Mark this question for sending on all interfaces
@@ -3593,7 +3695,7 @@ mDNSlocal void SendQueries(mDNS *const m)
for (q = m->Questions; q && q != m->NewQuestions; q=q->next)
{
if (mDNSOpaque16IsZero(q->TargetQID)
- && (q->SendQNow || (!q->Target.type && ActiveQuestion(q) && q->ThisQInterval <= maxExistingQuestionInterval && AccelerateThisQuery(m,q))))
+ && (q->SendQNow || (ActiveQuestion(q) && q->ThisQInterval <= maxExistingQuestionInterval && AccelerateThisQuery(m,q))))
{
// If at least halfway to next query time, advance to next interval
// If less than halfway to next query time, then
@@ -3792,21 +3894,9 @@ mDNSlocal void SendQueries(mDNS *const m)
else if ((Suppress = SuppressOnThisInterface(q->DupSuppress, intf)) ||
BuildQuestion(m, intf, &m->omsg, &queryptr, q, &kalistptr, &answerforecast))
{
- // We successfully added the question to the packet. Make sure that
- // we also send the NSEC3 record if required. BuildQuestion accounted for
- // the space.
- //
- // Note: We don't suppress anonymous questions and hence Suppress should always
- // be zero.
-
if (Suppress)
m->mDNSStats.DupQuerySuppressions++;
- if (!Suppress && q->AnonInfo)
- {
- debugf("SendQueries: marking for question %##s, Suppress %d", q->qname.c, Suppress);
- q->AnonInfo->SendNow = intf->InterfaceID;
- }
q->SendQNow = (q->InterfaceID || !q->SendOnAll) ? mDNSNULL : GetNextActiveInterfaceID(intf);
if (q->WakeOnResolveCount)
{
@@ -3815,7 +3905,7 @@ mDNSlocal void SendQueries(mDNS *const m)
}
// use background traffic class if any included question requires it
- if (q->UseBackgroundTrafficClass)
+ if (q->UseBackgroundTraffic)
{
useBackgroundTrafficClass = mDNStrue;
}
@@ -3920,24 +4010,6 @@ mDNSlocal void SendQueries(mDNS *const m)
}
}
- for (q = m->Questions; q; q = q->next)
- {
- if (q->AnonInfo && q->AnonInfo->SendNow == intf->InterfaceID)
- {
- mDNSu8 *newptr = PutResourceRecord(&m->omsg, queryptr, &m->omsg.h.numAuthorities, q->AnonInfo->nsec3RR);
- if (newptr)
- {
- debugf("SendQueries: Added NSEC3 record %s on InterfaceID %p", RRDisplayString(m, q->AnonInfo->nsec3RR), intf->InterfaceID);
- queryptr = newptr;
- }
- else
- {
- LogMsg("SendQueries: ERROR!! Cannot add NSEC3 record %s on InterfaceID %p", RRDisplayString(m, q->AnonInfo->nsec3RR), intf->InterfaceID);
- }
- q->AnonInfo->SendNow = mDNSNULL;
- }
- }
-
if (queryptr > m->omsg.data)
{
// If we have data to send, add OWNER/TRACER/OWNER+TRACER option if necessary, then send packet
@@ -3981,12 +4053,12 @@ mDNSlocal void SendQueries(mDNS *const m)
if ((m->omsg.h.flags.b[0] & kDNSFlag0_TC) && m->omsg.h.numQuestions > 1)
LogMsg("SendQueries: Should not have more than one question (%d) in a truncated packet", m->omsg.h.numQuestions);
- debugf("SendQueries: Sending %d Question%s %d Answer%s %d Update%s on %p",
+ debugf("SendQueries: Sending %d Question%s %d Answer%s %d Update%s on %d (%s)",
m->omsg.h.numQuestions, m->omsg.h.numQuestions == 1 ? "" : "s",
m->omsg.h.numAnswers, m->omsg.h.numAnswers == 1 ? "" : "s",
- m->omsg.h.numAuthorities, m->omsg.h.numAuthorities == 1 ? "" : "s", intf->InterfaceID);
- if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, mDNSNULL, &AllDNSLinkGroup_v4, MulticastDNSPort, mDNSNULL, mDNSNULL, useBackgroundTrafficClass);
- if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, mDNSNULL, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, mDNSNULL, useBackgroundTrafficClass);
+ m->omsg.h.numAuthorities, m->omsg.h.numAuthorities == 1 ? "" : "s", IIDPrintable(intf->InterfaceID), intf->ifname);
+ if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, mDNSNULL, mDNSNULL, &AllDNSLinkGroup_v4, MulticastDNSPort, mDNSNULL, useBackgroundTrafficClass);
+ if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, mDNSNULL, mDNSNULL, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, useBackgroundTrafficClass);
if (!m->SuppressSending) m->SuppressSending = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+9)/10);
if (++pktcount >= 1000)
{ LogMsg("SendQueries exceeded loop limit %d: giving up", pktcount); break; }
@@ -4012,7 +4084,7 @@ mDNSlocal void SendQueries(mDNS *const m)
{
if (ar->ARType != AuthRecordLocalOnly && ar->ARType != AuthRecordP2P)
LogInfo("SendQueries: No active interface %d to send probe: %d %s",
- (uint32_t)ar->SendRNow, (uint32_t)ar->resrec.InterfaceID, ARDisplayString(m, ar));
+ IIDPrintable(ar->SendRNow), IIDPrintable(ar->resrec.InterfaceID), ARDisplayString(m, ar));
ar->SendRNow = mDNSNULL;
}
@@ -4047,7 +4119,7 @@ mDNSlocal void SendQueries(mDNS *const m)
// so don't log the warning in that case.
if (q->InterfaceID != mDNSInterface_BLE)
LogInfo("SendQueries: No active interface %d to send %s question: %d %##s (%s)",
- (uint32_t)q->SendQNow, x ? "new" : "old", (uint32_t)q->InterfaceID, q->qname.c, DNSTypeName(q->qtype));
+ IIDPrintable(q->SendQNow), x ? "new" : "old", IIDPrintable(q->InterfaceID), q->qname.c, DNSTypeName(q->qtype));
q->SendQNow = mDNSNULL;
}
q->CachedAnswerNeedsUpdate = mDNSfalse;
@@ -4111,12 +4183,52 @@ mDNSlocal void ResetQuestionState(mDNS *const m, DNSQuestion *q)
q->RecentAnswerPkts = 0;
q->ThisQInterval = MaxQuestionInterval;
q->RequestUnicast = 0;
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
// Reset unansweredQueries so that we don't penalize this server later when we
// start sending queries when the cache expires.
q->unansweredQueries = 0;
+#endif
debugf("ResetQuestionState: Set MaxQuestionInterval for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
}
+mDNSlocal void AdjustUnansweredQueries(mDNS *const m, CacheRecord *const rr)
+{
+ const mDNSs32 expireTime = RRExpireTime(rr);
+ const mDNSu32 interval = TicksTTL(rr) / 20; // Calculate 5% of the cache record's TTL.
+ mDNSu32 rem;
+
+ // If the record is expired or UnansweredQueries is already at the max, then return early.
+ if (((m->timenow - expireTime) >= 0) || (rr->UnansweredQueries >= MaxUnansweredQueries)) return;
+
+ if (interval == 0)
+ {
+ LogInfo("AdjustUnansweredQueries: WARNING: unusually small TTL (%d ticks) for %s", TicksTTL(rr), CRDisplayString(m, rr));
+ return;
+ }
+
+ // Calculate the number of whole 5% TTL intervals between now and expiration time.
+ rem = ((mDNSu32)(expireTime - m->timenow)) / interval;
+
+ // Calculate the expected number of remaining refresher queries.
+ // Refresher queries are sent at the start of the last MaxUnansweredQueries intervals.
+ if (rem > MaxUnansweredQueries) rem = MaxUnansweredQueries;
+
+ // If the current number of remaining refresher queries is greater than expected, then at least one refresher query time
+ // was missed. This can happen if the cache record didn't have an active question during any of the times at which
+ // refresher queries would have been sent if the cache record did have an active question. The cache record's
+ // UnansweredQueries count needs to be adjusted to avoid a burst of refresher queries being sent in an attempt to make up
+ // for lost time. UnansweredQueries is set to the number of queries that would have been sent had the cache record had an
+ // active question from the 80% point of its lifetime up to now, with one exception: if the number of expected remaining
+ // refresher queries is zero (because timenow is beyond the 95% point), then UnansweredQueries is set to
+ // MaxUnansweredQueries - 1 so that at least one refresher query is sent before the cache record expires.
+ // Note: The cast is safe because rem is never greater than MaxUnansweredQueries; the comparison has to be signed.
+ if ((MaxUnansweredQueries - rr->UnansweredQueries) > (mDNSs32)rem)
+ {
+ if (rem == 0) rem++;
+ rr->UnansweredQueries = (mDNSu8)(MaxUnansweredQueries - rem);
+ }
+}
+
// Note: AnswerCurrentQuestionWithResourceRecord can call a user callback, which may change the record list and/or question list.
// Any code walking either list must use the m->CurrentQuestion (and possibly m->CurrentRecord) mechanism to protect against this.
// In fact, to enforce this, the routine will *only* answer the question currently pointed to by m->CurrentQuestion,
@@ -4130,25 +4242,6 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco
q->CurrentAnswers, AddRecord ? "Add" : "Rmv", MortalityDisplayString(rr->resrec.mortality),
rr->resrec.rroriginalttl, CRDisplayString(m, rr));
- // When the response for the question was validated, the entire rrset was validated. If we deliver
- // a RMV for a single record in the rrset, we invalidate the response. If we deliver another add
- // in the future, we will do the revalidation again.
- //
- // Also, if we deliver an ADD for a negative cache record and it has no NSEC/NSEC3, the ValidationStatus needs
- // to be reset. This happens normally when we deliver a "secure" negative response followed by an insecure
- // negative response which can happen e.g., when disconnecting from network that leads to a negative response
- // due to no DNS servers. As we don't deliver RMVs for negative responses that were delivered before, we need
- // to do it on the next ADD of a negative cache record. This ADD could be the result of a timeout, no DNS servers
- // etc. in which case we need to reset the state to make sure we don't deliver them as secure. If this is
- // a real negative response, we would reset the state here and validate the results at the end of this function.
- // or the real response again if we purge the cache.
- if (q->ValidationRequired && ((AddRecord == QC_rmv) ||
- (rr->resrec.RecordType == kDNSRecordTypePacketNegative && (AddRecord == QC_add))))
- {
- q->ValidationStatus = 0;
- q->ValidationState = DNSSECValRequired;
- }
-
// Normally we don't send out the unicast query if we have answered using our local only auth records e.g., /etc/hosts.
// But if the query for "A" record has a local answer but query for "AAAA" record has no local answer, we might
// send the AAAA query out which will come back with CNAME and will also answer the "A" query. To prevent that,
@@ -4161,7 +4254,7 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco
return;
}
- if (QuerySuppressed(q))
+ if (q->Suppressed && (AddRecord != QC_suppressed))
{
// If the query is suppressed, then we don't want to answer from the cache. But if this query is
// supposed to time out, we still want to callback the clients. We do this only for TimeoutQuestions
@@ -4174,17 +4267,33 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco
if (AddRecord == QC_add && Question_uDNS(q) && rr->resrec.RecordType != kDNSRecordTypePacketNegative &&
q->allowExpired != AllowExpired_None && rr->resrec.mortality == Mortality_Mortal ) rr->resrec.mortality = Mortality_Immortal; // Update a non-expired cache record to immortal if appropriate
-#if AWD_METRICS
- if ((AddRecord == QC_add) && Question_uDNS(q) && !followcname)
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
+ if ((AddRecord == QC_add) && Question_uDNS(q) && !followcname && !q->metrics.answered)
{
- const domainname * queryName;
- mDNSu32 responseLatencyMs;
- mDNSBool isForCellular;
-
- queryName = q->metrics.originalQName ? q->metrics.originalQName : &q->qname;
- isForCellular = (q->qDNSServer && q->qDNSServer->cellIntf);
- if (!q->metrics.answered)
+ mDNSBool skipUpdate = mDNSfalse;
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ if (!q->dnsservice || (mdns_dns_service_get_resolver_type(q->dnsservice) != mdns_resolver_type_normal))
+ {
+ skipUpdate = mDNStrue;
+ }
+#endif
+ if (!skipUpdate)
{
+ const domainname * queryName;
+ mDNSu32 responseLatencyMs, querySendCount;
+ mDNSBool isForCellular;
+
+ queryName = q->metrics.originalQName ? q->metrics.originalQName : &q->qname;
+ querySendCount = q->metrics.querySendCount;
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ if (q->querier)
+ {
+ querySendCount += mdns_querier_get_send_count(q->querier);
+ }
+ isForCellular = mdns_dns_service_interface_is_cellular(q->dnsservice);
+#else
+ isForCellular = (q->qDNSServer && q->qDNSServer->isCell);
+#endif
if (q->metrics.querySendCount > 0)
{
responseLatencyMs = ((m->timenow - q->metrics.firstQueryTime) * 1000) / mDNSPlatformOneSecond;
@@ -4193,14 +4302,10 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco
{
responseLatencyMs = 0;
}
-
- MetricsUpdateDNSQueryStats(queryName, q->qtype, &rr->resrec, q->metrics.querySendCount, q->metrics.expiredAnswerState, responseLatencyMs, isForCellular);
- q->metrics.answered = mDNStrue;
- }
- if (q->metrics.querySendCount > 0)
- {
- MetricsUpdateDNSResolveStats(queryName, &rr->resrec, isForCellular);
+ MetricsUpdateDNSQueryStats(queryName, q->qtype, &rr->resrec, querySendCount, q->metrics.expiredAnswerState,
+ q->metrics.dnsOverTCPState, responseLatencyMs, isForCellular);
}
+ q->metrics.answered = mDNStrue;
}
#endif
// Note: Use caution here. In the case of records with rr->DelayDelivery set, AnswerCurrentQuestionWithResourceRecord(... mDNStrue)
@@ -4209,10 +4314,14 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco
if (AddRecord == QC_add && !q->DuplicateOf && rr->CRActiveQuestion != q && rr->resrec.mortality != Mortality_Ghost)
{
- if (!rr->CRActiveQuestion) m->rrcache_active++; // If not previously active, increment rrcache_active count
debugf("AnswerCurrentQuestionWithResourceRecord: Updating CRActiveQuestion from %p to %p for cache record %s, CurrentAnswer %d",
rr->CRActiveQuestion, q, CRDisplayString(m,rr), q->CurrentAnswers);
- rr->CRActiveQuestion = q; // We know q is non-null
+ if (!rr->CRActiveQuestion)
+ {
+ m->rrcache_active++; // If not previously active, increment rrcache_active count
+ AdjustUnansweredQueries(m, rr); // Adjust UnansweredQueries in case the record missed out on refresher queries
+ }
+ rr->CRActiveQuestion = q; // We know q is non-null
SetNextCacheCheckTimeForRecord(m, rr);
}
@@ -4232,7 +4341,7 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco
if (rr->DelayDelivery) return; // We'll come back later when CacheRecordDeferredAdd() calls us
-#if USE_DNS64
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
// If DNS64StateMachine() returns true, then the question was restarted as a different question, so return.
if (!mDNSOpaque16IsZero(q->TargetQID) && DNS64StateMachine(m, q, &rr->resrec, AddRecord)) return;
#endif
@@ -4272,51 +4381,43 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco
mDNS_DropLockBeforeCallback(); // Allow client (and us) to legally make mDNS API calls
if (q->qtype != kDNSType_NSEC && RRAssertsNonexistence(&rr->resrec, q->qtype))
{
- CacheRecord neg;
- MakeNegativeCacheRecord(m, &neg, &q->qname, q->qnamehash, q->qtype, q->qclass, 1, rr->resrec.InterfaceID, q->qDNSServer);
- q->QuestionCallback(m, q, &neg.resrec, AddRecord);
+ if (mDNSOpaque16IsZero(q->TargetQID))
+ {
+ CacheRecord neg;
+ #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ mDNSPlatformMemZero(&neg, sizeof(neg));
+ MakeNegativeCacheRecord(m, &neg, &q->qname, q->qnamehash, q->qtype, q->qclass, 1, rr->resrec.InterfaceID, q->dnsservice);
+ #else
+ MakeNegativeCacheRecord(m, &neg, &q->qname, q->qnamehash, q->qtype, q->qclass, 1, rr->resrec.InterfaceID, q->qDNSServer);
+ #endif
+ q->QuestionCallback(m, q, &neg.resrec, AddRecord);
+ }
}
else
{
-#if USE_DNS64
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
if (DNS64ShouldAnswerQuestion(q, &rr->resrec))
{
- DNS64AnswerQuestion(m, q, &rr->resrec, AddRecord);
+ DNS64AnswerCurrentQuestion(m, &rr->resrec, AddRecord);
}
else
#endif
{
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+ get_denial_records_from_negative_cache_to_dnssec_context(q->DNSSECStatus.enable_dnssec,
+ q->DNSSECStatus.context, rr);
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
q->QuestionCallback(m, q, &rr->resrec, AddRecord);
}
}
mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
}
- // If this is an "Add" operation and this question needs validation, validate the response.
- // In the case of negative responses, extra care should be taken. Negative cache records are
- // used for many purposes. For example,
- //
- // 1) Suppressing questions (SuppressUnusable)
- // 2) Timeout questions
- // 3) The name does not exist
- // 4) No DNS servers are available and we need a quick response for the application
- //
- // (1) and (2) are handled by "QC_add" check as AddRecord would be "QC_forceresponse" or "QC_suppressed"
- // in that case. For (3), it is possible that we don't get nsecs back but we still need to call
- // VerifySignature so that we can deliver the appropriate DNSSEC result. There is no point in verifying
- // signature for (4) and hence the explicit check for q->qDNSServer.
- //
- if (m->CurrentQuestion == q && (AddRecord == QC_add) && !q->ValidatingResponse && q->ValidationRequired &&
- q->ValidationState == DNSSECValRequired && q->qDNSServer)
- {
- q->ValidationState = DNSSECValInProgress;
- // Treat it as callback call as that's what dnssec code expects
- mDNS_DropLockBeforeCallback(); // Allow client (and us) to legally make mDNS API calls
- VerifySignature(m, mDNSNULL, q);
- mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
- return;
- }
+ // Note: Proceed with caution after this point because client callback function
+ // invoked above is allowed to do anything, such as starting/stopping queries
+ // (including this one itself, or the next or previous query in the linked list),
+ // registering/deregistering records, starting/stopping NAT traversals, etc.
- if ((m->CurrentQuestion == q) && !ValidatingQuestion(q))
+ if (m->CurrentQuestion == q)
{
// If we get a CNAME back while we are validating the response (i.e., CNAME for DS, DNSKEY, RRSIG),
// don't follow them. If it is a ValidationRequired question, wait for the CNAME to be validated
@@ -4333,9 +4434,9 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco
}
}
-mDNSlocal void CacheRecordDeferredAdd(mDNS *const m, CacheRecord *rr)
+mDNSlocal void CacheRecordDeferredAdd(mDNS *const m, CacheRecord *cr)
{
- rr->DelayDelivery = 0;
+ cr->DelayDelivery = 0;
if (m->CurrentQuestion)
LogMsg("CacheRecordDeferredAdd ERROR m->CurrentQuestion already set: %##s (%s)",
m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
@@ -4343,8 +4444,8 @@ mDNSlocal void CacheRecordDeferredAdd(mDNS *const m, CacheRecord *rr)
while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
{
DNSQuestion *q = m->CurrentQuestion;
- if (ResourceRecordAnswersQuestion(&rr->resrec, q))
- AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add);
+ if (CacheRecordAnswersQuestion(cr, q))
+ AnswerCurrentQuestionWithResourceRecord(m, cr, QC_add);
if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
m->CurrentQuestion = q->next;
}
@@ -4381,7 +4482,7 @@ mDNSlocal mDNSs32 CheckForSoonToExpireRecords(mDNS *const m, const domainname *c
// Note: CacheRecordAdd calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
// which may change the record list and/or question list.
// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
-mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr)
+mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *cr)
{
DNSQuestion *q;
@@ -4389,7 +4490,7 @@ mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr)
// counters here we'll end up double-incrementing them when we do it again in AnswerNewQuestion().
for (q = m->Questions; q && q != m->NewQuestions; q=q->next)
{
- if (ResourceRecordAnswersQuestion(&rr->resrec, q))
+ if (CacheRecordAnswersQuestion(cr, q))
{
mDNSIPPort zp = zeroIPPort;
// If this question is one that's actively sending queries, and it's received ten answers within one
@@ -4411,28 +4512,30 @@ mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr)
SetNextQueryTime(m,q);
}
}
- verbosedebugf("CacheRecordAdd %p %##s (%s) %lu %#a:%d question %p", rr, rr->resrec.name->c,
- DNSTypeName(rr->resrec.rrtype), rr->resrec.rroriginalttl, rr->resrec.rDNSServer ?
- &rr->resrec.rDNSServer->addr : mDNSNULL, mDNSVal16(rr->resrec.rDNSServer ?
- rr->resrec.rDNSServer->port : zp), q);
+ verbosedebugf("CacheRecordAdd %p %##s (%s) %lu %#a:%d question %p", cr, cr->resrec.name->c,
+ DNSTypeName(cr->resrec.rrtype), cr->resrec.rroriginalttl, cr->resrec.rDNSServer ?
+ &cr->resrec.rDNSServer->addr : mDNSNULL, mDNSVal16(cr->resrec.rDNSServer ?
+ cr->resrec.rDNSServer->port : zeroIPPort), q);
q->CurrentAnswers++;
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
q->unansweredQueries = 0;
- if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
- if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
+#endif
+ if (cr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
+ if (cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
if (q->CurrentAnswers > 4000)
{
static int msgcount = 0;
if (msgcount++ < 10)
LogMsg("CacheRecordAdd: %##s (%s) has %d answers; shedding records to resist DOS attack",
q->qname.c, DNSTypeName(q->qtype), q->CurrentAnswers);
- rr->resrec.rroriginalttl = 0;
- rr->UnansweredQueries = MaxUnansweredQueries;
+ cr->resrec.rroriginalttl = 0;
+ cr->UnansweredQueries = MaxUnansweredQueries;
}
}
}
- if (!rr->DelayDelivery)
+ if (!cr->DelayDelivery)
{
if (m->CurrentQuestion)
LogMsg("CacheRecordAdd ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
@@ -4440,15 +4543,15 @@ mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr)
while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
{
q = m->CurrentQuestion;
- if (ResourceRecordAnswersQuestion(&rr->resrec, q))
- AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add);
+ if (CacheRecordAnswersQuestion(cr, q))
+ AnswerCurrentQuestionWithResourceRecord(m, cr, QC_add);
if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
m->CurrentQuestion = q->next;
}
m->CurrentQuestion = mDNSNULL;
}
- SetNextCacheCheckTimeForRecord(m, rr);
+ SetNextCacheCheckTimeForRecord(m, cr);
}
// NoCacheAnswer is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call.
@@ -4461,7 +4564,7 @@ mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr)
// Note: NoCacheAnswer calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
// which may change the record list and/or question list.
// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
-mDNSlocal void NoCacheAnswer(mDNS *const m, CacheRecord *rr)
+mDNSlocal void NoCacheAnswer(mDNS *const m, CacheRecord *cr)
{
LogMsg("No cache space: Delivering non-cached result for %##s", m->rec.r.resrec.name->c);
if (m->CurrentQuestion)
@@ -4472,8 +4575,8 @@ mDNSlocal void NoCacheAnswer(mDNS *const m, CacheRecord *rr)
while (m->CurrentQuestion)
{
DNSQuestion *q = m->CurrentQuestion;
- if (ResourceRecordAnswersQuestion(&rr->resrec, q))
- AnswerCurrentQuestionWithResourceRecord(m, rr, QC_addnocache); // QC_addnocache means "don't expect remove events for this"
+ if (CacheRecordAnswersQuestion(cr, q))
+ AnswerCurrentQuestionWithResourceRecord(m, cr, QC_addnocache); // QC_addnocache means "don't expect remove events for this"
if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
m->CurrentQuestion = q->next;
}
@@ -4484,12 +4587,12 @@ mDNSlocal void NoCacheAnswer(mDNS *const m, CacheRecord *rr)
// Note that CacheRecordRmv is *only* called for records that are referenced by at least one active question.
// If new questions are created as a result of invoking client callbacks, they will be added to
// the end of the question list, and m->NewQuestions will be set to indicate the first new question.
-// rr is an existing cache CacheRecord that just expired and is being deleted
+// cr is an existing cache CacheRecord that just expired and is being deleted
// (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique).
// Note: CacheRecordRmv calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
// which may change the record list and/or question list.
// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
-mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr)
+mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *cr)
{
if (m->CurrentQuestion)
LogMsg("CacheRecordRmv ERROR m->CurrentQuestion already set: %##s (%s)",
@@ -4505,24 +4608,26 @@ mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr)
// response. A cache may be present that answers this question e.g., cache entry generated
// before the question became suppressed. We need to skip the suppressed questions here as
// the RMV event has already been generated.
- if (!QuerySuppressed(q) && ResourceRecordAnswersQuestion(&rr->resrec, q) &&
- (q->allowExpired == AllowExpired_None || rr->resrec.mortality == Mortality_Mortal))
+ if (!q->Suppressed && CacheRecordAnswersQuestion(cr, q) &&
+ (q->allowExpired == AllowExpired_None || cr->resrec.mortality == Mortality_Mortal))
{
- verbosedebugf("CacheRecordRmv %p %s", rr, CRDisplayString(m, rr));
+ verbosedebugf("CacheRecordRmv %p %s", cr, CRDisplayString(m, cr));
q->FlappingInterface1 = mDNSNULL;
q->FlappingInterface2 = mDNSNULL;
- if (q->CurrentAnswers == 0) {
- mDNSIPPort zp = zeroIPPort;
+ if (q->CurrentAnswers == 0)
+ {
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
LogMsg("CacheRecordRmv ERROR!!: How can CurrentAnswers already be zero for %p %##s (%s) DNSServer %#a:%d",
q, q->qname.c, DNSTypeName(q->qtype), q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL,
- mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zp));
- }
+ mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort));
+#endif
+ }
else
{
q->CurrentAnswers--;
- if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers--;
- if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers--;
+ if (cr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers--;
+ if (cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers--;
}
// If we have dropped below the answer threshold for this mDNS question,
@@ -4535,15 +4640,15 @@ mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr)
LogInfo("CacheRecordRmv: (%s) %##s dropped below threshold of %d answers",
DNSTypeName(q->qtype), q->qname.c, q->BrowseThreshold);
}
- if (rr->resrec.rdata->MaxRDLength) // Never generate "remove" events for negative results
+ if (cr->resrec.rdata->MaxRDLength) // Never generate "remove" events for negative results
{
if ((q->CurrentAnswers == 0) && mDNSOpaque16IsZero(q->TargetQID))
{
LogInfo("CacheRecordRmv: Last answer for %##s (%s) expired from cache; will reconfirm antecedents",
q->qname.c, DNSTypeName(q->qtype));
- ReconfirmAntecedents(m, &q->qname, q->qnamehash, rr->resrec.InterfaceID, 0);
+ ReconfirmAntecedents(m, &q->qname, q->qnamehash, cr->resrec.InterfaceID, 0);
}
- AnswerCurrentQuestionWithResourceRecord(m, rr, QC_rmv);
+ AnswerCurrentQuestionWithResourceRecord(m, cr, QC_rmv);
}
}
if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
@@ -4554,7 +4659,7 @@ mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr)
mDNSlocal void ReleaseCacheEntity(mDNS *const m, CacheEntity *e)
{
-#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1
+#if MDNS_MALLOC_DEBUGGING >= 1
unsigned int i;
for (i=0; i<sizeof(*e); i++) ((char*)e)[i] = 0xFF;
#endif
@@ -4600,8 +4705,6 @@ mDNSlocal void ReleaseAdditionalCacheRecords(mDNS *const m, CacheRecord **rp)
if (!rr->resrec.InterfaceID)
{
m->rrcache_totalused_unicast -= rr->resrec.rdlength;
- if (DNSSECRecordType(rr->resrec.rrtype))
- BumpDNSSECStats(m, kStatsActionDecrement, kStatsTypeMemoryUsage, rr->resrec.rdlength);
}
ReleaseCacheEntity(m, (CacheEntity *)rr);
}
@@ -4614,6 +4717,13 @@ mDNSexport void ReleaseCacheRecord(mDNS *const m, CacheRecord *r)
//LogMsg("ReleaseCacheRecord: Releasing %s", CRDisplayString(m, r));
if (r->resrec.rdata && r->resrec.rdata != (RData*)&r->smallrdatastorage) mDNSPlatformMemFree(r->resrec.rdata);
r->resrec.rdata = mDNSNULL;
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ mdns_forget(&r->resrec.dnsservice);
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+ release_denial_records_in_cache_record(r);
+#endif
cg = CacheGroupForRecord(m, &r->resrec);
@@ -4632,21 +4742,11 @@ mDNSexport void ReleaseCacheRecord(mDNS *const m, CacheRecord *r)
}
r->resrec.name = mDNSNULL;
- if (r->resrec.AnonInfo)
- {
- debugf("ReleaseCacheRecord: freeing AnonInfo for %##s (%s)", r->resrec.name->c, DNSTypeName(r->resrec.rrtype));
- FreeAnonInfo((void *)r->resrec.AnonInfo);
- }
- r->resrec.AnonInfo = mDNSNULL;
-
if (!r->resrec.InterfaceID)
{
m->rrcache_totalused_unicast -= r->resrec.rdlength;
- if (DNSSECRecordType(r->resrec.rrtype))
- BumpDNSSECStats(m, kStatsActionDecrement, kStatsTypeMemoryUsage, r->resrec.rdlength);
}
- ReleaseAdditionalCacheRecords(m, &r->nsec);
ReleaseAdditionalCacheRecords(m, &r->soa);
ReleaseCacheEntity(m, (CacheEntity *)r);
@@ -4681,7 +4781,8 @@ mDNSlocal void CheckCacheExpiration(mDNS *const m, const mDNSu32 slot, CacheGrou
// a normal deferred ADD case, then AnswerCurrentQuestionWithResourceRecord will reset it to
// MaxQuestionInterval. If we have inactive questions referring to negative cache entries,
// don't ressurect them as they will deliver duplicate "No such Record" ADD events
- if (!mDNSOpaque16IsZero(q->TargetQID) && !q->LongLived && ActiveQuestion(q))
+ if (((mDNSOpaque16IsZero(q->TargetQID) && (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask)) ||
+ (!mDNSOpaque16IsZero(q->TargetQID) && !q->LongLived)) && ActiveQuestion(q))
{
q->ThisQInterval = InitialQuestionInterval;
q->LastQTime = m->timenow - q->ThisQInterval;
@@ -4693,6 +4794,7 @@ mDNSlocal void CheckCacheExpiration(mDNS *const m, const mDNSu32 slot, CacheGrou
event += MAX_GHOST_TIME; // Adjust so we can check for a ghost expiration
if (rr->resrec.mortality == Mortality_Mortal || // Normal expired mortal record that needs released
+ rr->resrec.rroriginalttl == 0 || // Non-mortal record that is set to be purged
(rr->resrec.mortality == Mortality_Ghost && m->timenow - event >= 0)) // A ghost record that expired more than MAX_GHOST_TIME ago
{ // Release as normal
*rp = rr->next; // Cut it from the list before ReleaseCacheRecord
@@ -4838,45 +4940,29 @@ mDNSlocal mDNSBool AnswerQuestionWithLORecord(mDNS *const m, DNSQuestion *q, mDN
// Today, we suppress questions (not send them on the wire) for several reasons e.g.,
// AAAA query is suppressed because no IPv6 capability or PID is not allowed to make
-// DNS requests. We need to temporarily suspend the suppress status so that we can
-// deliver a negative response (AnswerCurrentQuestionWithResourceRecord does not answer
-// suppressed questions) and reset it back. In the future, if there are other
-// reasons for suppressing the query, this function should be updated.
+// DNS requests.
mDNSlocal void AnswerSuppressedQuestion(mDNS *const m, DNSQuestion *q)
{
- mDNSBool SuppressQuery;
- mDNSBool DisallowPID;
-
- // If the client did not set the kDNSServiceFlagsReturnIntermediates flag, then don't generate a negative response, just
- // deactivate the DNSQuestion.
- if (!q->ReturnIntermed)
+ // If the client did not set the kDNSServiceFlagsReturnIntermediates flag, then don't generate a negative response,
+ // just deactivate the DNSQuestion.
+ if (q->ReturnIntermed)
+ {
+ GenerateNegativeResponse(m, mDNSInterface_Any, QC_suppressed);
+ }
+ else
{
q->ThisQInterval = 0;
- return;
}
-
- SuppressQuery = q->SuppressQuery;
- DisallowPID = q->DisallowPID;
-
- // make sure that QuerySuppressed() returns false
- q->SuppressQuery = mDNSfalse;
- q->DisallowPID = mDNSfalse;
-
- GenerateNegativeResponse(m, mDNSInterface_Any, QC_suppressed);
-
- q->SuppressQuery = SuppressQuery;
- q->DisallowPID = DisallowPID;
}
mDNSlocal void AnswerNewQuestion(mDNS *const m)
{
mDNSBool ShouldQueryImmediately = mDNStrue;
DNSQuestion *const q = m->NewQuestions; // Grab the question we're going to answer
-#if USE_DNS64
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
if (!mDNSOpaque16IsZero(q->TargetQID)) DNS64HandleNewQuestion(m, q);
#endif
CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname);
- mDNSBool AnsweredFromCache = mDNSfalse;
verbosedebugf("AnswerNewQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
@@ -4906,15 +4992,26 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m)
// If the client's question callback deletes the question, then m->CurrentQuestion will
// be advanced, and we'll exit out of the loop
m->lock_rrcache = 1;
- if (m->CurrentQuestion)
- LogMsg("AnswerNewQuestion ERROR m->CurrentQuestion already set: %##s (%s)",
- m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+ if (m->CurrentQuestion) {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%d->Q%d] AnswerNewQuestion ERROR m->CurrentQuestion already set: " PRI_DM_NAME " (" PUB_S ")",
+ m->CurrentQuestion->request_id, mDNSVal16(m->CurrentQuestion->TargetQID),
+ DM_NAME_PARAM(&m->CurrentQuestion->qname), DNSTypeName(m->CurrentQuestion->qtype));
+ }
+
m->CurrentQuestion = q; // Indicate which question we're answering, so we'll know if it gets deleted
if (q->NoAnswer == NoAnswer_Fail)
{
- LogMsg("AnswerNewQuestion: NoAnswer_Fail %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%d->Q%d] AnswerNewQuestion: NoAnswer_Fail " PRI_DM_NAME " (" PUB_S ")",
+ q->request_id, mDNSVal16(q->TargetQID), DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype));
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any, q->dnsservice);
+#else
MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any, q->qDNSServer);
+#endif
q->NoAnswer = NoAnswer_Normal; // Temporarily turn off answer suppression
AnswerCurrentQuestionWithResourceRecord(m, &m->rec.r, QC_addnocache);
// Don't touch the question if it has been stopped already
@@ -4933,66 +5030,67 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m)
if (AnswerQuestionWithLORecord(m, q, mDNSfalse))
goto exit;
- // If we are not supposed to answer this question, generate a negative response.
- // Temporarily suspend the SuppressQuery so that AnswerCurrentQuestionWithResourceRecord can answer the question
- //
// If it is a question trying to validate some response, it already checked the cache for a response. If it still
// reissues a question it means it could not find the RRSIGs. So, we need to bypass the cache check and send
// the question out.
- if (QuerySuppressed(q))
+ if (q->Suppressed)
{
AnswerSuppressedQuestion(m, q);
}
- else if (!q->ValidatingResponse)
+ else
{
- CacheRecord *rr;
- for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
- if (SameNameRecordAnswersQuestion(&rr->resrec, q))
+ CacheRecord *cr;
+ for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
+ if (SameNameCacheRecordAnswersQuestion(cr, q))
{
// SecsSinceRcvd is whole number of elapsed seconds, rounded down
- mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - rr->TimeRcvd)) / mDNSPlatformOneSecond;
- if (rr->resrec.rroriginalttl <= SecsSinceRcvd && q->allowExpired != AllowExpired_AllowExpiredAnswers) continue; // Go to next one in loop
+ mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - cr->TimeRcvd)) / mDNSPlatformOneSecond;
+ mDNSBool IsExpired = (cr->resrec.rroriginalttl <= SecsSinceRcvd);
+ if (IsExpired && q->allowExpired != AllowExpired_AllowExpiredAnswers) continue; // Go to next one in loop
// If this record set is marked unique, then that means we can reasonably assume we have the whole set
// -- we don't need to rush out on the network and query immediately to see if there are more answers out there
- if ((rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) || (q->ExpectUnique))
+ if ((cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) || (q->ExpectUnique))
ShouldQueryImmediately = mDNSfalse;
q->CurrentAnswers++;
- if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
- if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
- AnsweredFromCache = mDNStrue;
-#if AWD_METRICS
- if (q->metrics.expiredAnswerState == ExpiredAnswer_Allowed) q->metrics.expiredAnswerState = ExpiredAnswer_AnsweredWithExpired;
+ if (cr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
+ if (cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
+ if (q->metrics.expiredAnswerState == ExpiredAnswer_Allowed) q->metrics.expiredAnswerState = IsExpired ? ExpiredAnswer_AnsweredWithExpired : ExpiredAnswer_AnsweredWithCache;
#endif
- AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add);
+#if MDNSRESPONDER_SUPPORTS(APPLE, CACHE_ANALYTICS)
+ cr->LastCachedAnswerTime = m->timenow;
+ dnssd_analytics_update_cache_request(mDNSOpaque16IsZero(q->TargetQID) ? CacheRequestType_multicast : CacheRequestType_unicast, CacheState_hit);
+#endif
+ AnswerCurrentQuestionWithResourceRecord(m, cr, QC_add);
if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here
}
- else if (mDNSOpaque16IsZero(q->TargetQID) && RRTypeIsAddressType(rr->resrec.rrtype) && RRTypeIsAddressType(q->qtype))
+ else if (mDNSOpaque16IsZero(q->TargetQID) && RRTypeIsAddressType(cr->resrec.rrtype) && RRTypeIsAddressType(q->qtype))
ShouldQueryImmediately = mDNSfalse;
}
// We don't use LogInfo for this "Question deleted" message because it happens so routinely that
// it's not remotely remarkable, and therefore unlikely to be of much help tracking down bugs.
if (m->CurrentQuestion != q) { debugf("AnswerNewQuestion: Question deleted while giving cache answers"); goto exit; }
- // Neither a local record nor a cache entry could answer this question. If this question need to be retried
- // with search domains, generate a negative response which will now retry after appending search domains.
- // If the query was suppressed above, we already generated a negative response. When it gets unsuppressed,
- // we will retry with search domains.
- if (!QuerySuppressed(q) && !AnsweredFromCache && q->RetryWithSearchDomains)
- {
- LogInfo("AnswerNewQuestion: Generating response for retrying with search domains %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- GenerateNegativeResponse(m, mDNSInterface_Any, QC_forceresponse);
- }
-
- if (m->CurrentQuestion != q) { debugf("AnswerNewQuestion: Question deleted while giving negative answer"); goto exit; }
-
+#if MDNSRESPONDER_SUPPORTS(APPLE, CACHE_ANALYTICS)
+ dnssd_analytics_update_cache_request(mDNSOpaque16IsZero(q->TargetQID) ? CacheRequestType_multicast : CacheRequestType_unicast, CacheState_miss);
+#endif
+ q->InitialCacheMiss = mDNStrue; // Initial cache check is done, so mark as a miss from now on
if (q->allowExpired == AllowExpired_AllowExpiredAnswers)
{
q->allowExpired = AllowExpired_MakeAnswersImmortal; // After looking through the cache for an answer, demote to make immortal
if (q->firstExpiredQname.c[0]) // If an original query name was saved on an expired answer, start it over in case it is updated
{
- LogMsg("AnswerNewQuestion: Restarting original question %p firstExpiredQname %##s for allowExpiredAnswers question", q, &q->firstExpiredQname.c);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%d->Q%d] AnswerNewQuestion: Restarting original question %p firstExpiredQname " PRI_DM_NAME " for allowExpiredAnswers question",
+ q->request_id, mDNSVal16(q->TargetQID), q, DM_NAME_PARAM(&q->firstExpiredQname));
mDNS_StopQuery_internal(m, q); // Stop old query
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ if (!SameDomainName(&q->qname, &q->firstExpiredQname))
+ {
+ Querier_PrepareQuestionForUnwindRestart(q);
+ }
+#endif
AssignDomainName(&q->qname, &q->firstExpiredQname); // Update qname
q->qnamehash = DomainNameHashValue(&q->qname); // and namehash
mDNS_StartQuery_internal(m, q); // start new query
@@ -5005,7 +5103,7 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m)
// Hence we don't execute the following block of code for those cases.
if (ShouldQueryImmediately && ActiveQuestion(q))
{
- debugf("AnswerNewQuestion: ShouldQueryImmediately %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ debugf("[R%d->Q%d] AnswerNewQuestion: ShouldQueryImmediately %##s (%s)", q->request_id, mDNSVal16(q->TargetQID), q->qname.c, DNSTypeName(q->qtype));
q->ThisQInterval = InitialQuestionInterval;
q->LastQTime = m->timenow - q->ThisQInterval;
if (mDNSOpaque16IsZero(q->TargetQID)) // For mDNS, spread packets to avoid a burst of simultaneous queries
@@ -5062,7 +5160,7 @@ mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m)
if (LocalOnlyRecordAnswersQuestion(rr, q))
{
retEv = mDNStrue;
- AnswerLocalQuestionWithLocalAuthRecord(m, rr, mDNStrue);
+ AnswerLocalQuestionWithLocalAuthRecord(m, rr, QC_add);
if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here
}
}
@@ -5074,12 +5172,12 @@ mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m)
while (m->CurrentRecord && m->CurrentRecord != m->NewLocalRecords)
{
- AuthRecord *rr = m->CurrentRecord;
- m->CurrentRecord = rr->next;
- if (ResourceRecordAnswersQuestion(&rr->resrec, q))
+ AuthRecord *ar = m->CurrentRecord;
+ m->CurrentRecord = ar->next;
+ if (AuthRecordAnswersQuestion(ar, q))
{
retEv = mDNStrue;
- AnswerLocalQuestionWithLocalAuthRecord(m, rr, mDNStrue);
+ AnswerLocalQuestionWithLocalAuthRecord(m, ar, QC_add);
if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here
}
}
@@ -5105,8 +5203,11 @@ mDNSlocal CacheEntity *GetCacheEntity(mDNS *const m, const CacheGroup *const Pre
if (!m->rrcache_free && m->MainCallback)
{
if (m->rrcache_totalused != m->rrcache_size)
- LogMsg("GetFreeCacheRR: count mismatch: m->rrcache_totalused %lu != m->rrcache_size %lu",
- m->rrcache_totalused, m->rrcache_size);
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "GetFreeCacheRR: count mismatch: m->rrcache_totalused %u != m->rrcache_size %u",
+ m->rrcache_totalused, m->rrcache_size);
+ }
// We don't want to be vulnerable to a malicious attacker flooding us with an infinite
// number of bogus records so that we keep growing our cache until the machine runs out of memory.
@@ -5114,8 +5215,11 @@ mDNSlocal CacheEntity *GetCacheEntity(mDNS *const m, const CacheGroup *const Pre
// and we're actively using less than 1/32 of that cache, then we purge all the unused records
// and recycle them, instead of allocating more memory.
if (m->rrcache_size > 5000 && m->rrcache_size / 32 > m->rrcache_active)
- LogInfo("Possible denial-of-service attack in progress: m->rrcache_size %lu; m->rrcache_active %lu",
- m->rrcache_size, m->rrcache_active);
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "Possible denial-of-service attack in progress: m->rrcache_size %u; m->rrcache_active %u",
+ m->rrcache_size, m->rrcache_active);
+ }
else
{
mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
@@ -5156,8 +5260,8 @@ mDNSlocal CacheEntity *GetCacheEntity(mDNS *const m, const CacheGroup *const Pre
else ReleaseCacheGroup(m, cp);
}
}
- LogInfo("GetCacheEntity recycled %d records to reduce cache from %d to %d",
- oldtotalused - m->rrcache_totalused, oldtotalused, m->rrcache_totalused);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "GetCacheEntity recycled %d records to reduce cache from %d to %d",
+ oldtotalused - m->rrcache_totalused, oldtotalused, m->rrcache_totalused);
}
if (m->rrcache_free) // If there are records in the free list, take one
@@ -5166,7 +5270,7 @@ mDNSlocal CacheEntity *GetCacheEntity(mDNS *const m, const CacheGroup *const Pre
m->rrcache_free = e->next;
if (++m->rrcache_totalused >= m->rrcache_report)
{
- LogInfo("RR Cache now using %ld objects", m->rrcache_totalused);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "RR Cache now using %u objects", m->rrcache_totalused);
if (m->rrcache_report < 100) m->rrcache_report += 10;
else if (m->rrcache_report < 1000) m->rrcache_report += 100;
else m->rrcache_report += 1000;
@@ -5187,7 +5291,7 @@ mDNSlocal CacheRecord *GetCacheRecord(mDNS *const m, CacheGroup *cg, mDNSu16 RDL
r->resrec.rdata = (RData*)&r->smallrdatastorage; // By default, assume we're usually going to be using local storage
if (RDLength > InlineCacheRDSize) // If RDLength is too big, allocate extra storage
{
- r->resrec.rdata = (RData*)mDNSPlatformMemAllocate(sizeofRDataHeader + RDLength);
+ r->resrec.rdata = (RData*) mDNSPlatformMemAllocateClear(sizeofRDataHeader + RDLength);
if (r->resrec.rdata) r->resrec.rdata->MaxRDLength = r->resrec.rdlength = RDLength;
else { ReleaseCacheEntity(m, (CacheEntity*)r); r = mDNSNULL; }
}
@@ -5205,7 +5309,7 @@ mDNSlocal CacheGroup *GetCacheGroup(mDNS *const m, const mDNSu32 slot, const Res
cg->members = mDNSNULL;
cg->rrcache_tail = &cg->members;
if (namelen > sizeof(cg->namestorage))
- cg->name = mDNSPlatformMemAllocate(namelen);
+ cg->name = (domainname *) mDNSPlatformMemAllocate(namelen);
else
cg->name = (domainname*)cg->namestorage;
if (!cg->name)
@@ -5444,7 +5548,7 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
mDNS_SendKeepalives(m);
}
-#if BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
if (m->NextBonjourDisableTime && (m->timenow - m->NextBonjourDisableTime >= 0))
{
// Schedule immediate network change processing to leave the multicast group
@@ -5455,15 +5559,12 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
LogInfo("mDNS_Execute: Scheduled network changed processing to leave multicast group.");
}
-#endif // BONJOUR_ON_DEMAND
+#endif
// Clear AnnounceOwner if necessary. (Do this *before* SendQueries() and SendResponses().)
if (m->AnnounceOwner && m->timenow - m->AnnounceOwner >= 0)
{
m->AnnounceOwner = 0;
-
- // This is a good time to reset the delay counter used to prevent spurious conflicts
- m->DelayConflictProcessing = 0;
}
if (m->DelaySleep && m->timenow - m->DelaySleep >= 0)
@@ -5560,6 +5661,7 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
{
m->NewLocalOnlyRecords = mDNSfalse;
for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
+ {
for (ag = m->rrauth.rrauth_hash[slot]; ag; ag = ag->next)
{
for (i=0; i<100 && ag->NewLocalOnlyRecords; i++)
@@ -5577,6 +5679,7 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
// We limit about 100 per AuthGroup that can be serviced at a time
if (i >= 100) LogMsg("mDNS_Execute: ag->NewLocalOnlyRecords exceeded loop limit");
}
+ }
}
// 5. See what packets we need to send
@@ -5698,34 +5801,15 @@ mDNSlocal mDNSBool QuestionHasLocalAnswers(mDNS *const m, DNSQuestion *q)
// In cases 2 and 3 we do want to cause the question to be resent immediately (ScheduleImmediately is true)
mDNSlocal void ActivateUnicastQuery(mDNS *const m, DNSQuestion *const question, mDNSBool ScheduleImmediately)
{
- // For now this AutoTunnel stuff is specific to Mac OS X.
- // In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer
-#if APPLE_OSX_mDNSResponder
- // Even though BTMM client tunnels are only useful for AAAA queries, we need to treat v4 and v6 queries equally.
- // Otherwise we can get the situation where the A query completes really fast (with an NXDOMAIN result) and the
- // caller then gives up waiting for the AAAA result while we're still in the process of setting up the tunnel.
- // To level the playing field, we block both A and AAAA queries while tunnel setup is in progress, and then
- // returns results for both at the same time. If we are looking for the _autotunnel6 record, then skip this logic
- // as this would trigger looking up _autotunnel6._autotunnel6 and end up failing the original query.
-
- if (RRTypeIsAddressType(question->qtype) && PrivateQuery(question) &&
- !SameDomainLabel(question->qname.c, (const mDNSu8 *)"\x0c_autotunnel6")&& question->QuestionCallback != AutoTunnelCallback)
- {
- question->NoAnswer = NoAnswer_Suspended;
- AddNewClientTunnel(question);
- return;
- }
-#endif // APPLE_OSX_mDNSResponder
-
if (!question->DuplicateOf)
{
- debugf("ActivateUnicastQuery: %##s %s%s%s",
- question->qname.c, DNSTypeName(question->qtype), PrivateQuery(question) ? " (Private)" : "", ScheduleImmediately ? " ScheduleImmediately" : "");
+ debugf("ActivateUnicastQuery: %##s %s%s",
+ question->qname.c, DNSTypeName(question->qtype), ScheduleImmediately ? " ScheduleImmediately" : "");
question->CNAMEReferrals = 0;
if (question->nta) { CancelGetZoneData(m, question->nta); question->nta = mDNSNULL; }
if (question->LongLived)
{
- question->state = LLQ_InitialRequest;
+ question->state = LLQ_Init;
question->id = zeroOpaque64;
question->servPort = zeroIPPort;
if (question->tcp) { DisposeTCPConn(question->tcp); question->tcp = mDNSNULL; }
@@ -5813,23 +5897,13 @@ mDNSexport void mDNSCoreRestartAddressQueries(mDNS *const m, mDNSBool SearchDoma
// If the query is suppressed, the RMV events won't be delivered
if (!CacheRecordRmvEventsForQuestion(m, q)) { LogInfo("mDNSCoreRestartAddressQueries: Question deleted while delivering Cache Record RMV events"); continue; }
- // SuppressQuery status does not affect questions that are answered using local records
+ // Suppressed status does not affect questions that are answered using local records
if (!LocalRecordRmvEventsForQuestion(m, q)) { LogInfo("mDNSCoreRestartAddressQueries: Question deleted while delivering Local Record RMV events"); continue; }
- LogInfo("mDNSCoreRestartAddressQueries: Stop question %p %##s (%s), AppendSearchDomains %d, qnameOrig %p", q,
- q->qname.c, DNSTypeName(q->qtype), q->AppendSearchDomains, q->qnameOrig);
+ LogInfo("mDNSCoreRestartAddressQueries: Stop question %p %##s (%s), AppendSearchDomains %d", q,
+ q->qname.c, DNSTypeName(q->qtype), q->AppendSearchDomains);
mDNS_StopQuery_internal(m, q);
- // Reset state so that it looks like it was in the beginning i.e it should look at /etc/hosts, cache
- // and then search domains should be appended. At the beginning, qnameOrig was NULL.
- if (q->qnameOrig)
- {
- LogInfo("mDNSCoreRestartAddressQueries: qnameOrig %##s", q->qnameOrig);
- AssignDomainName(&q->qname, q->qnameOrig);
- mDNSPlatformMemFree(q->qnameOrig);
- q->qnameOrig = mDNSNULL;
- q->RetryWithSearchDomains = ApplySearchDomainsFirst(q) ? 1 : 0;
- }
- q->SearchListIndex = 0;
+ if (q->ResetHandler) q->ResetHandler(q);
q->next = restart;
restart = q;
}
@@ -5863,7 +5937,13 @@ mDNSexport void mDNSCoreRestartQueries(mDNS *const m)
{
q = m->CurrentQuestion;
m->CurrentQuestion = m->CurrentQuestion->next;
- if (!mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q)) ActivateUnicastQuery(m, q, mDNStrue);
+ if (!mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q))
+ {
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ mdns_querier_forget(&q->querier);
+#endif
+ ActivateUnicastQuery(m, q, mDNStrue);
+ }
}
#endif
@@ -6130,7 +6210,7 @@ mDNSexport mStatus UpdateKeepaliveRData(mDNS *const m, AuthRecord *rr, NetworkIn
newrdlength += 2;
rdsize = newrdlength > sizeof(RDataBody) ? newrdlength : sizeof(RDataBody);
- newrd = mDNSPlatformMemAllocate(sizeof(RData) - sizeof(RDataBody) + rdsize);
+ newrd = (RData *) mDNSPlatformMemAllocate(sizeof(RData) - sizeof(RDataBody) + rdsize);
if (!newrd) { LogMsg("UpdateKeepaliveRData: ptr NULL"); return mStatus_NoMemoryErr; }
newrd->MaxRDLength = (mDNSu16) rdsize;
@@ -6284,7 +6364,7 @@ mDNSlocal void SendSPSRegistrationForOwner(mDNS *const m, NetworkInterfaceInfo *
LogSPS("SendSPSRegistration: Sending Update %s %d (%d) id %5d with %d records %d bytes to %#a:%d", intf->ifname, intf->NextSPSAttempt, sps,
mDNSVal16(m->omsg.h.id), m->omsg.h.mDNS_numUpdates, p - m->omsg.data, &intf->SPSAddr[sps], mDNSVal16(intf->SPSPort[sps]));
// if (intf->NextSPSAttempt < 5) m->omsg.h.flags = zeroID; // For simulating packet loss
- err = mDNSSendDNSMessage(m, &m->omsg, p, intf->InterfaceID, mDNSNULL, &intf->SPSAddr[sps], intf->SPSPort[sps], mDNSNULL, mDNSNULL, mDNSfalse);
+ err = mDNSSendDNSMessage(m, &m->omsg, p, intf->InterfaceID, mDNSNULL, mDNSNULL, &intf->SPSAddr[sps], intf->SPSPort[sps], mDNSNULL, mDNSfalse);
if (err) LogSPS("SendSPSRegistration: mDNSSendDNSMessage err %d", err);
if (err && intf->SPSAddr[sps].type == mDNSAddrType_IPv4 && intf->NetWakeResolve[sps].ThisQInterval == -1)
{
@@ -6313,15 +6393,13 @@ mDNSlocal mDNSBool RecordIsFirstOccurrenceOfOwner(mDNS *const m, const AuthRecor
mDNSlocal void mDNSCoreStoreProxyRR(mDNS *const m, const mDNSInterfaceID InterfaceID, AuthRecord *const rr)
{
- AuthRecord *newRR = mDNSPlatformMemAllocate(sizeof(AuthRecord));
-
+ AuthRecord *newRR = (AuthRecord *) mDNSPlatformMemAllocateClear(sizeof(*newRR));
if (newRR == mDNSNULL)
{
LogSPS("%s : could not allocate memory for new resource record", __func__);
return;
}
- mDNSPlatformMemZero(newRR, sizeof(AuthRecord));
mDNS_SetupResourceRecord(newRR, mDNSNULL, InterfaceID, rr->resrec.rrtype,
rr->resrec.rroriginalttl, rr->resrec.RecordType,
rr->ARType, mDNSNULL, mDNSNULL);
@@ -6729,9 +6807,6 @@ mDNSlocal void BeginSleepProcessing(mDNS *const m)
// which is okay because with no outstanding resolves, or updates in flight,
// mDNSCoreReadyForSleep() will conclude correctly that all the updates have already completed
- // Setting this flag activates the SleepLimit which delays sleep by 5 seconds and
- // will allow the system to deregister any BTMM records.
- m->NextScheduledSPRetry = m->timenow + (5 * mDNSPlatformOneSecond);
registeredIntfIDS[registeredCount] = intf->InterfaceID;
registeredCount++;
}
@@ -6846,7 +6921,8 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
{
AuthRecord *rr;
- LogSPS("%s (old state %d) at %ld", sleep ? "Sleeping" : "Waking", m->SleepState, m->timenow);
+ LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_INFO,
+ PUB_S " (old state %d) at %d", sleep ? "Sleeping" : "Waking", m->SleepState, m->timenow);
if (sleep && !m->SleepState) // Going to sleep
{
@@ -6875,7 +6951,8 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
if (m->SystemWakeOnLANEnabled && m->DelaySleep)
{
// If we just woke up moments ago, allow ten seconds for networking to stabilize before going back to sleep
- LogSPS("mDNSCoreMachineSleep: Re-sleeping immediately after waking; will delay for %d ticks", m->DelaySleep - m->timenow);
+ LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_DEBUG,
+ "mDNSCoreMachineSleep: Re-sleeping immediately after waking; will delay for %d ticks", m->DelaySleep - m->timenow);
m->SleepLimit = NonZeroTime(m->DelaySleep + mDNSPlatformOneSecond * 10);
}
else
@@ -6883,18 +6960,19 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
m->DelaySleep = 0;
m->SleepLimit = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 10);
m->mDNSStats.Sleeps++;
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ Querier_HandleSleep();
+#endif
BeginSleepProcessing(m);
}
#ifndef UNICAST_DISABLED
SuspendLLQs(m);
#endif
-#if APPLE_OSX_mDNSResponder
- RemoveAutoTunnel6Record(m);
-#endif
- LogSPS("mDNSCoreMachineSleep: m->SleepState %d (%s) seq %d", m->SleepState,
- m->SleepState == SleepState_Transferring ? "Transferring" :
- m->SleepState == SleepState_Sleeping ? "Sleeping" : "?", m->SleepSeqNum);
+ LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_DEBUG, "mDNSCoreMachineSleep: m->SleepState %d (" PUB_S ") seq %d",
+ m->SleepState,
+ m->SleepState == SleepState_Transferring ? "Transferring" :
+ m->SleepState == SleepState_Sleeping ? "Sleeping" : "?", m->SleepSeqNum);
mDNS_Unlock(m);
}
else if (!sleep) // Waking up
@@ -6927,16 +7005,19 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
mDNSCoreBeSleepProxyServer_internal(m, m->SPSType, m->SPSPortability, m->SPSMarginalPower, m->SPSTotalPower, m->SPSFeatureFlags);
}
m->mDNSStats.Wakes++;
- m->DelayConflictProcessing = MAX_CONFLICT_PROCESSING_DELAYS;
// ... and the same for NextSPSAttempt
for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) intf->NextSPSAttempt = -1;
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ Querier_HandleWake();
+#endif
// Restart unicast and multicast queries
mDNSCoreRestartQueries(m);
// and reactivtate service registrations
m->NextSRVUpdate = NonZeroTime(m->timenow + mDNSPlatformOneSecond);
- LogInfo("mDNSCoreMachineSleep waking: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
+ LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_DEBUG,
+ "mDNSCoreMachineSleep waking: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
// 2. Re-validate our cache records
currtime = mDNSPlatformUTC();
@@ -6972,21 +7053,25 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
if (diff >= remain || diff > (2 * 24 * 3600))
{
- LogInfo("mDNSCoreMachineSleep: %s: Purging cache entry SleptTime %d, Remaining TTL %d",
- CRDisplayString(m, cr), diff, remain);
+ LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_DEBUG,
+ "mDNSCoreMachineSleep: " PRI_S ": Purging cache entry SleptTime %d, Remaining TTL %d",
+ CRDisplayString(m, cr), diff, remain);
mDNS_PurgeCacheResourceRecord(m, cr);
continue;
}
cr->TimeRcvd -= (diff * mDNSPlatformOneSecond);
if (m->timenow - (cr->TimeRcvd + ((mDNSs32)uTTL * mDNSPlatformOneSecond)) >= 0)
{
- LogInfo("mDNSCoreMachineSleep: %s: Purging after adjusting the remaining TTL %d by %d seconds",
- CRDisplayString(m, cr), remain, diff);
+ LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_DEBUG,
+ "mDNSCoreMachineSleep: " PRI_S ": Purging after adjusting the remaining TTL %d by %d seconds",
+ CRDisplayString(m, cr), remain, diff);
mDNS_PurgeCacheResourceRecord(m, cr);
}
else
{
- LogInfo("mDNSCoreMachineSleep: %s: Adjusted the remain ttl %u by %d seconds", CRDisplayString(m, cr), remain, diff);
+ LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_DEBUG,
+ "mDNSCoreMachineSleep: " PRI_S ": Adjusted the remain ttl %u by %d seconds",
+ CRDisplayString(m, cr), remain, diff);
}
}
}
@@ -7016,7 +7101,7 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
// But if we do get a network configuration change, mDNSMacOSXNetworkChanged will call uDNS_SetupDNSConfig, which
// will call mDNS_SetPrimaryInterfaceInfo, which will call RecreateNATMappings to refresh them, potentially sooner
// than five seconds from now.
- LogInfo("mDNSCoreMachineSleep: recreating NAT mappings in 5 seconds");
+ LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_DEBUG, "mDNSCoreMachineSleep: recreating NAT mappings in 5 seconds");
RecreateNATMappings(m, mDNSPlatformOneSecond * 5);
mDNS_Unlock(m);
}
@@ -7086,9 +7171,6 @@ mDNSexport mDNSBool mDNSCoreReadyForSleep(mDNS *m, mDNSs32 now)
{
if (rr->state == regState_Refresh && rr->tcp)
{ LogSPS("mDNSCoreReadyForSleep: waiting for Record updateIntID 0x%x 0x%x (updateid %d) %s", rr->updateIntID.l[1], rr->updateIntID.l[0], mDNSVal16(rr->updateid), ARDisplayString(m,rr)); goto notready; }
- #if APPLE_OSX_mDNSResponder
- if (!RecordReadyForSleep(rr)) { LogSPS("mDNSCoreReadyForSleep: waiting for %s", ARDisplayString(m, rr)); goto notready; }
- #endif
}
mDNS_Unlock(m);
@@ -7134,7 +7216,7 @@ notready:
return mDNSfalse;
}
-mDNSexport mDNSs32 mDNSCoreIntervalToNextWake(mDNS *const m, mDNSs32 now)
+mDNSexport mDNSs32 mDNSCoreIntervalToNextWake(mDNS *const m, mDNSs32 now, mDNSNextWakeReason *outReason)
{
AuthRecord *ar;
@@ -7143,13 +7225,19 @@ mDNSexport mDNSs32 mDNSCoreIntervalToNextWake(mDNS *const m, mDNSs32 now)
// E.g. we might wake up and find no wireless network because the base station got rebooted just at that moment,
// and if that happens we don't want to just give up and go back to sleep and never try again.
mDNSs32 e = now + (120 * 60 * mDNSPlatformOneSecond); // Sleep for at most 120 minutes
+ mDNSNextWakeReason reason = mDNSNextWakeReason_UpkeepWake;
NATTraversalInfo *nat;
for (nat = m->NATTraversals; nat; nat=nat->next)
+ {
if (nat->Protocol && nat->ExpiryTime && nat->ExpiryTime - now > mDNSPlatformOneSecond*4)
{
mDNSs32 t = nat->ExpiryTime - (nat->ExpiryTime - now) / 10; // Wake up when 90% of the way to the expiry time
- if (e - t > 0) e = t;
+ if ((e - t) > 0)
+ {
+ e = t;
+ reason = mDNSNextWakeReason_NATPortMappingRenewal;
+ }
LogSPS("ComputeWakeTime: %p %s Int %5d Ext %5d Err %d Retry %5d Interval %5d Expire %5d Wake %5d",
nat, nat->Protocol == NATOp_MapTCP ? "TCP" : "UDP",
mDNSVal16(nat->IntPort), mDNSVal16(nat->ExternalPort), nat->Result,
@@ -7158,21 +7246,30 @@ mDNSexport mDNSs32 mDNSCoreIntervalToNextWake(mDNS *const m, mDNSs32 now)
nat->ExpiryTime ? (nat->ExpiryTime - now) / mDNSPlatformOneSecond : 0,
(t - now) / mDNSPlatformOneSecond);
}
-
+ }
// This loop checks both the time we need to renew wide-area registrations,
// and the time we need to renew Sleep Proxy registrations
for (ar = m->ResourceRecords; ar; ar = ar->next)
+ {
if (ar->expire && ar->expire - now > mDNSPlatformOneSecond*4)
{
mDNSs32 t = ar->expire - (ar->expire - now) / 10; // Wake up when 90% of the way to the expiry time
- if (e - t > 0) e = t;
+ if ((e - t) > 0)
+ {
+ e = t;
+ reason = mDNSNextWakeReason_RecordRegistrationRenewal;
+ }
LogSPS("ComputeWakeTime: %p Int %7d Next %7d Expire %7d Wake %7d %s",
ar, ar->ThisAPInterval / mDNSPlatformOneSecond,
(ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond,
ar->expire ? (ar->expire - now) / mDNSPlatformOneSecond : 0,
(t - now) / mDNSPlatformOneSecond, ARDisplayString(m, ar));
}
-
+ }
+ if (outReason)
+ {
+ *outReason = reason;
+ }
return(e - now);
}
@@ -7191,7 +7288,7 @@ mDNSlocal mDNSu8 *GenerateUnicastResponse(const DNSMessage *const query, const m
const mDNSu8 *const limit = response->data + sizeof(response->data);
const mDNSu8 *ptr = query->data;
AuthRecord *rr;
- mDNSu32 maxttl = mDNSMaximumTTLSeconds;
+ mDNSu32 maxttl = (!InterfaceID) ? mDNSMaximumUnicastTTLSeconds : mDNSMaximumMulticastTTLSeconds;
int i;
// Initialize the response fields so we can answer the questions
@@ -7262,6 +7359,12 @@ mDNSlocal int CompareRData(const AuthRecord *const our, const CacheRecord *const
if (!our) { LogMsg("CompareRData ERROR: our is NULL"); return(+1); }
if (!pkt) { LogMsg("CompareRData ERROR: pkt is NULL"); return(+1); }
+#if defined(__clang_analyzer__)
+ // Get rid of analyzer warnings about ourptr and pktptr pointing to garbage after retruning from putRData().
+ // There are no clear indications from the analyzer of the cause of the supposed problem.
+ mDNSPlatformMemZero(ourdata, 1);
+ mDNSPlatformMemZero(pktdata, 1);
+#endif
ourend = putRData(mDNSNULL, ourdata, ourdata + sizeof(ourdata), &our->resrec);
pktend = putRData(mDNSNULL, pktdata, pktdata + sizeof(pktdata), &pkt->resrec);
while (ourptr < ourend && pktptr < pktend && *ourptr == *pktptr) { ourptr++; pktptr++; }
@@ -7276,6 +7379,17 @@ mDNSlocal int CompareRData(const AuthRecord *const our, const CacheRecord *const
return(-1);
}
+mDNSlocal mDNSBool PacketRecordMatches(const AuthRecord *const rr, const CacheRecord *const pktrr, const AuthRecord *const master)
+{
+ if (IdenticalResourceRecord(&rr->resrec, &pktrr->resrec))
+ {
+ const AuthRecord *r2 = rr;
+ while (r2->DependentOn) r2 = r2->DependentOn;
+ if (r2 == master) return(mDNStrue);
+ }
+ return(mDNSfalse);
+}
+
// See if we have an authoritative record that's identical to this packet record,
// whose canonical DependentOn record is the specified master record.
// The DependentOn pointer is typically used for the TXT record of service registrations
@@ -7290,21 +7404,11 @@ mDNSlocal mDNSBool MatchDependentOn(const mDNS *const m, const CacheRecord *cons
const AuthRecord *r1;
for (r1 = m->ResourceRecords; r1; r1=r1->next)
{
- if (IdenticalResourceRecord(&r1->resrec, &pktrr->resrec))
- {
- const AuthRecord *r2 = r1;
- while (r2->DependentOn) r2 = r2->DependentOn;
- if (r2 == master) return(mDNStrue);
- }
+ if (PacketRecordMatches(r1, pktrr, master)) return(mDNStrue);
}
for (r1 = m->DuplicateRecords; r1; r1=r1->next)
{
- if (IdenticalResourceRecord(&r1->resrec, &pktrr->resrec))
- {
- const AuthRecord *r2 = r1;
- while (r2->DependentOn) r2 = r2->DependentOn;
- if (r2 == master) return(mDNStrue);
- }
+ if (PacketRecordMatches(r1, pktrr, master)) return(mDNStrue);
}
return(mDNSfalse);
}
@@ -7320,8 +7424,7 @@ mDNSlocal const AuthRecord *FindRRSet(const mDNS *const m, const CacheRecord *co
{
if (IdenticalResourceRecord(&rr->resrec, &pktrr->resrec))
{
- while (rr->RRSet && rr != rr->RRSet) rr = rr->RRSet;
- return(rr);
+ return(rr->RRSet ? rr->RRSet : rr);
}
}
return(mDNSNULL);
@@ -7374,7 +7477,7 @@ mDNSlocal void ResolveSimultaneousProbe(mDNS *const m, const DNSMessage *const q
{
ptr = GetLargeResourceRecord(m, query, ptr, end, q->InterfaceID, kDNSRecordTypePacketAuth, &m->rec);
if (!ptr) break;
- if (m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && ResourceRecordAnswersQuestion(&m->rec.r.resrec, q))
+ if (m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && CacheRecordAnswersQuestion(&m->rec.r, q))
{
FoundUpdate = mDNStrue;
if (PacketRRConflict(m, our, &m->rec.r))
@@ -7425,9 +7528,13 @@ mDNSlocal CacheRecord *FindIdenticalRecordInCache(const mDNS *const m, const Res
{
if (!pktrr->InterfaceID)
{
- mDNSu16 id1 = (pktrr->rDNSServer ? pktrr->rDNSServer->resGroupID : 0);
- mDNSu16 id2 = (rr->resrec.rDNSServer ? rr->resrec.rDNSServer->resGroupID : 0);
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ match = (pktrr->dnsservice == rr->resrec.dnsservice) ? mDNStrue : mDNSfalse;
+#else
+ const mDNSu32 id1 = (pktrr->rDNSServer ? pktrr->rDNSServer->resGroupID : 0);
+ const mDNSu32 id2 = (rr->resrec.rDNSServer ? rr->resrec.rDNSServer->resGroupID : 0);
match = (id1 == id2);
+#endif
}
else match = (pktrr->InterfaceID == rr->resrec.InterfaceID);
@@ -7538,7 +7645,7 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
const mDNSAddr *srcaddr, const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, mDNSBool QueryWasMulticast,
mDNSBool QueryWasLocalUnicast, DNSMessage *const response)
{
- mDNSBool FromLocalSubnet = srcaddr && mDNS_AddressIsLocalSubnet(m, InterfaceID, srcaddr);
+ const mDNSBool FromLocalSubnet = mDNS_AddressIsLocalSubnet(m, InterfaceID, srcaddr);
AuthRecord *ResponseRecords = mDNSNULL;
AuthRecord **nrp = &ResponseRecords;
@@ -7556,7 +7663,6 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
mDNSu8 *responseptr = mDNSNULL;
AuthRecord *rr;
int i;
- CacheRecord *McastNSEC3Records = mDNSNULL;
// ***
// *** 1. Look in Additional Section for an OPT record
@@ -7581,12 +7687,6 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
}
- //
- // Look in Authority Section for NSEC3 record
- //
-
- mDNSParseNSEC3Records(m, query, end, InterfaceID, &McastNSEC3Records);
-
// ***
// *** 2. Parse Question Section and mark potential answers
// ***
@@ -7600,9 +7700,6 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
ptr = getQuestion(query, ptr, end, InterfaceID, &pktq); // get the question...
if (!ptr) goto exit;
- pktq.AnonInfo = mDNSNULL;
- if (McastNSEC3Records)
- InitializeAnonInfoForQuestion(m, &McastNSEC3Records, &pktq);
// The only queries that *need* a multicast response are:
// * Queries sent via multicast
// * from port 5353
@@ -7634,7 +7731,7 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
{
rr = m->CurrentRecord;
m->CurrentRecord = rr->next;
- if (AnyTypeRecordAnswersQuestion(&rr->resrec, &pktq) && (QueryWasMulticast || QueryWasLocalUnicast || rr->AllowRemoteQuery))
+ if (AnyTypeRecordAnswersQuestion(rr, &pktq) && (QueryWasMulticast || QueryWasLocalUnicast || rr->AllowRemoteQuery))
{
m->mDNSStats.MatchingAnswersForQueries++;
if (RRTypeAnswersQuestionType(&rr->resrec, pktq.qtype))
@@ -7644,12 +7741,6 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
else if (ResourceRecordIsValidAnswer(rr))
{
NumAnswersForThisQuestion++;
- // As we have verified this question to be part of the same subset,
- // set the anonymous data which is needed below when walk the cache
- // records to see what answers we should be expecting. The cache records
- // may cache only the nsec3RR and not the anonymous data itself.
- if (pktq.AnonInfo && rr->resrec.AnonInfo)
- SetAnonData(&pktq, &rr->resrec, mDNStrue);
// Note: We should check here if this is a probe-type query, and if so, generate an immediate
// unicast answer back to the source, because timeliness in answering probes is important.
@@ -7711,12 +7802,16 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
// Make a list indicating which of our own cache records we expect to see updated as a result of this query
// Note: Records larger than 1K are not habitually multicast, so don't expect those to be updated
for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
- if (SameNameRecordAnswersQuestion(&cr->resrec, &pktq) && cr->resrec.rdlength <= SmallRecordLimit)
+ {
+ if (SameNameCacheRecordAnswersQuestion(cr, &pktq) && cr->resrec.rdlength <= SmallRecordLimit)
+ {
if (!cr->NextInKAList && eap != &cr->NextInKAList)
{
*eap = cr;
eap = &cr->NextInKAList;
}
+ }
+ }
}
#endif // POOF_ENABLED
@@ -7724,25 +7819,23 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
// We only do this for non-truncated queries. Right now it would be too complicated to try
// to keep track of duplicate suppression state between multiple packets, especially when we
// can't guarantee to receive all of the Known Answer packets that go with a particular query.
- // For anonymous question, the duplicate suppressesion should happen if the
- // question belongs in the same group. As the group is expected to be
- // small, we don't do the optimization for now.
- if (!pktq.AnonInfo)
+ for (q = m->Questions; q; q=q->next)
{
- for (q = m->Questions; q; q=q->next)
- if (!q->Target.type && ActiveQuestion(q) && m->timenow - q->LastQTxTime > mDNSPlatformOneSecond / 4)
- if (!q->InterfaceID || q->InterfaceID == InterfaceID)
- if (q->NextInDQList == mDNSNULL && dqp != &q->NextInDQList)
- if (q->qtype == pktq.qtype &&
- q->qclass == pktq.qclass &&
- q->qnamehash == pktq.qnamehash && SameDomainName(&q->qname, &pktq.qname))
- { *dqp = q; dqp = &q->NextInDQList; }
+ if (ActiveQuestion(q) && m->timenow - q->LastQTxTime > mDNSPlatformOneSecond / 4)
+ {
+ if (!q->InterfaceID || q->InterfaceID == InterfaceID)
+ {
+ if (q->NextInDQList == mDNSNULL && dqp != &q->NextInDQList)
+ {
+ if (q->qtype == pktq.qtype &&
+ q->qclass == pktq.qclass &&
+ q->qnamehash == pktq.qnamehash && SameDomainName(&q->qname, &pktq.qname))
+ { *dqp = q; dqp = &q->NextInDQList; }
+ }
+ }
+ }
}
}
- if (pktq.AnonInfo)
- {
- FreeAnonInfo(pktq.AnonInfo);
- }
}
// ***
@@ -7830,7 +7923,7 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
while (*dqp)
{
DNSQuestion *q = *dqp;
- if (ResourceRecordAnswersQuestion(&m->rec.r.resrec, q))
+ if (CacheRecordAnswersQuestion(&m->rec.r, q))
{ *dqp = q->NextInDQList; q->NextInDQList = mDNSNULL; }
else dqp = &q->NextInDQList;
}
@@ -8025,13 +8118,6 @@ exit:
debugf("ProcessQuery: Recorded DSI for %##s (%s) on %p/%s", q->qname.c, DNSTypeName(q->qtype), InterfaceID,
srcaddr->type == mDNSAddrType_IPv4 ? "v4" : "v6");
}
-
- if (McastNSEC3Records)
- {
- debugf("ProcessQuery: McastNSEC3Records not used");
- FreeNSECRecords(m, McastNSEC3Records);
- }
-
return(responseptr);
}
@@ -8074,7 +8160,7 @@ mDNSlocal void mDNSCoreReceiveQuery(mDNS *const m, const DNSMessage *const msg,
m->omsg.h.numAnswers, m->omsg.h.numAnswers == 1 ? "" : "s",
m->omsg.h.numAdditionals, m->omsg.h.numAdditionals == 1 ? "" : "s",
srcaddr, mDNSVal16(srcport), InterfaceID, srcaddr->type);
- mDNSSendDNSMessage(m, &m->omsg, responseend, InterfaceID, mDNSNULL, srcaddr, srcport, mDNSNULL, mDNSNULL, mDNSfalse);
+ mDNSSendDNSMessage(m, &m->omsg, responseend, InterfaceID, mDNSNULL, mDNSNULL, srcaddr, srcport, mDNSNULL, mDNSfalse);
}
}
@@ -8095,7 +8181,8 @@ struct UDPSocket_struct
mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port
};
-mDNSlocal DNSQuestion *ExpectingUnicastResponseForQuestion(const mDNS *const m, const mDNSIPPort port, const mDNSOpaque16 id, const DNSQuestion *const question, mDNSBool tcp, DNSQuestion ** suspiciousQ)
+mDNSlocal DNSQuestion *ExpectingUnicastResponseForQuestion(const mDNS *const m, const mDNSIPPort port,
+ const mDNSOpaque16 id, const DNSQuestion *const question, mDNSBool tcp)
{
DNSQuestion *q;
for (q = m->Questions; q; q=q->next)
@@ -8110,7 +8197,6 @@ mDNSlocal DNSQuestion *ExpectingUnicastResponseForQuestion(const mDNS *const m,
if (mDNSSameOpaque16(q->TargetQID, id)) return(q);
else
{
- if (!tcp && suspiciousQ) *suspiciousQ = q;
return(mDNSNULL);
}
}
@@ -8125,7 +8211,6 @@ mDNSlocal DNSQuestion *ExpectingUnicastResponseForRecord(mDNS *const m,
{
DNSQuestion *q;
(void)id;
- (void)srcaddr;
for (q = m->Questions; q; q=q->next)
{
@@ -8154,8 +8239,8 @@ mDNSlocal DNSQuestion *ExpectingUnicastResponseForRecord(mDNS *const m,
// if (mDNSSameAddress(srcaddr, &q->Target)) return(mDNStrue);
// if (q->LongLived && mDNSSameAddress(srcaddr, &q->servAddr)) return(mDNStrue); Shouldn't need this now that we have LLQType checking
// if (TrustedSource(m, srcaddr)) return(mDNStrue);
- LogInfo("WARNING: Ignoring suspect uDNS response for %##s (%s) [q->Target %#a:%d] from %#a:%d %s",
- q->qname.c, DNSTypeName(q->qtype), &q->Target, mDNSVal16(srcp), srcaddr, mDNSVal16(port), CRDisplayString(m, rr));
+ LogInfo("WARNING: Ignoring suspect uDNS response for %##s (%s) from %#a:%d %s",
+ q->qname.c, DNSTypeName(q->qtype), srcaddr, mDNSVal16(port), CRDisplayString(m, rr));
return(mDNSNULL);
}
}
@@ -8198,21 +8283,18 @@ mDNSexport CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, C
if (!rr) NoCacheAnswer(m, &m->rec.r);
else
{
- RData *saveptr = rr->resrec.rdata; // Save the rr->resrec.rdata pointer
- *rr = m->rec.r; // Block copy the CacheRecord object
- rr->resrec.rdata = saveptr; // Restore rr->resrec.rdata after the structure assignment
- rr->resrec.name = cg->name; // And set rr->resrec.name to point into our CacheGroup header
- rr->resrec.mortality = Mortality_Mortal;
+ RData *saveptr = rr->resrec.rdata; // Save the rr->resrec.rdata pointer
+ *rr = m->rec.r; // Block copy the CacheRecord object
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ mdns_retain_null_safe(rr->resrec.dnsservice);
+#endif
+ rr->resrec.rdata = saveptr; // Restore rr->resrec.rdata after the structure assignment
+ rr->resrec.name = cg->name; // And set rr->resrec.name to point into our CacheGroup header
+ rr->resrec.mortality = Mortality_Mortal;
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+ rr->resrec.dnssec_result = dnssec_indeterminate; // Set the DNSSEC validation result of a record as "indeterminate" by default.
+#endif
- // We need to add the anonymous info before we call CacheRecordAdd so that
- // if it finds a matching question with this record, it bumps up the counters like
- // CurrentAnswers etc. Otherwise, when a cache entry gets removed, CacheRecordRmv
- // will complain.
- if (m->rec.r.resrec.AnonInfo)
- {
- rr->resrec.AnonInfo = m->rec.r.resrec.AnonInfo;
- m->rec.r.resrec.AnonInfo = mDNSNULL;
- }
rr->DelayDelivery = delay;
// If this is an oversized record with external storage allocated, copy rdata to external storage
@@ -8224,7 +8306,6 @@ mDNSexport CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, C
mDNSPlatformMemCopy(rr->resrec.rdata, m->rec.r.resrec.rdata, sizeofRDataHeader + RDLength);
rr->next = mDNSNULL; // Clear 'next' pointer
- rr->nsec = mDNSNULL;
rr->soa = mDNSNULL;
if (sourceAddress)
@@ -8233,10 +8314,15 @@ mDNSexport CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, C
if (!rr->resrec.InterfaceID)
{
m->rrcache_totalused_unicast += rr->resrec.rdlength;
- if (DNSSECRecordType(rr->resrec.rrtype))
- BumpDNSSECStats(m, kStatsActionIncrement, kStatsTypeMemoryUsage, rr->resrec.rdlength);
}
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+ if (rr != mDNSNULL)
+ {
+ rr->denial_of_existence_records = mDNSNULL;
+ }
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+
if (Add)
{
*(cg->rrcache_tail) = rr; // Append this record to tail of cache slot list
@@ -8247,7 +8333,7 @@ mDNSexport CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, C
{
// Can't use the "cg->name" if we are not adding to the cache as the
// CacheGroup may be released anytime if it is empty
- domainname *name = mDNSPlatformMemAllocate(DomainNameLength(cg->name));
+ domainname *name = (domainname *) mDNSPlatformMemAllocate(DomainNameLength(cg->name));
if (name)
{
AssignDomainName(name, cg->name);
@@ -8264,6 +8350,25 @@ mDNSexport CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, C
return(rr);
}
+mDNSlocal void RefreshCacheRecordCacheGroupOrder(CacheGroup *cg, CacheRecord *cr)
+{ // Move the cache record to the tail of the cache group to maintain a fresh ordering
+ if (cg->rrcache_tail != &cr->next) // If not already at the tail
+ {
+ CacheRecord **rp;
+ for (rp = &cg->members; *rp; rp = &(*rp)->next)
+ {
+ if (*rp == cr) // This item points to this record
+ {
+ *rp = cr->next; // Remove this record
+ break;
+ }
+ }
+ cr->next = mDNSNULL; // This record is now last
+ *(cg->rrcache_tail) = cr; // Append this record to tail of cache group
+ cg->rrcache_tail = &(cr->next); // Advance tail pointer
+ }
+}
+
mDNSlocal void RefreshCacheRecord(mDNS *const m, CacheRecord *rr, mDNSu32 ttl)
{
rr->TimeRcvd = m->timenow;
@@ -8322,13 +8427,12 @@ mDNSlocal mDNSu32 GetEffectiveTTL(const uDNS_LLQType LLQType, mDNSu32 ttl)
// When the response does not match the question directly, we still want to cache them sometimes. The current response is
// in m->rec.
-mDNSlocal mDNSBool IsResponseAcceptable(mDNS *const m, const CacheRecord *crlist, DNSQuestion *q, mDNSBool *nseclist)
+mDNSlocal mDNSBool IsResponseAcceptable(mDNS *const m, const CacheRecord *crlist)
{
CacheRecord *const newcr = &m->rec.r;
ResourceRecord *rr = &newcr->resrec;
const CacheRecord *cr;
- *nseclist = mDNSfalse;
for (cr = crlist; cr != (CacheRecord*)1; cr = cr->NextInCFList)
{
domainname *target = GetRRDomainNameTarget(&cr->resrec);
@@ -8344,138 +8448,18 @@ mDNSlocal mDNSBool IsResponseAcceptable(mDNS *const m, const CacheRecord *crlist
return (mDNStrue);
}
}
-
- // Either the question requires validation or we are validating a response with DNSSEC in which case
- // we need to accept the RRSIGs also so that we can validate the response. It is also possible that
- // we receive NSECs for our query which does not match the qname and we need to cache in that case
- // too. nseclist is set if they have to be cached as part of the negative cache record.
- if (q && DNSSECQuestion(q))
- {
- mDNSBool same = SameDomainName(&q->qname, rr->name);
- if (same && (q->qtype == rr->rrtype || rr->rrtype == kDNSType_CNAME))
- {
- LogInfo("IsResponseAcceptable: Accepting, same name and qtype %s, CR %s", DNSTypeName(q->qtype),
- CRDisplayString(m, newcr));
- return mDNStrue;
- }
- // We cache RRSIGS if it covers the question type or NSEC. If it covers a NSEC,
- // "nseclist" is set
- if (rr->rrtype == kDNSType_RRSIG)
- {
- RDataBody2 *const rdb = (RDataBody2 *)newcr->smallrdatastorage.data;
- rdataRRSig *rrsig = &rdb->rrsig;
- mDNSu16 typeCovered = swap16(rrsig->typeCovered);
-
- // Note the ordering. If we are looking up the NSEC record, then the RRSIG's typeCovered
- // would match the qtype and they are cached normally as they are not used to prove the
- // non-existence of any name. In that case, it is like any other normal dnssec validation
- // and hence nseclist should not be set.
-
- if (same && ((typeCovered == q->qtype) || (typeCovered == kDNSType_CNAME)))
- {
- LogInfo("IsResponseAcceptable: Accepting RRSIG %s matches question type %s", CRDisplayString(m, newcr),
- DNSTypeName(q->qtype));
- return mDNStrue;
- }
- else if (typeCovered == kDNSType_NSEC || typeCovered == kDNSType_NSEC3)
- {
- LogInfo("IsResponseAcceptable: Accepting RRSIG %s matches %s type (nseclist = 1)", CRDisplayString(m, newcr), DNSTypeName(typeCovered));
- *nseclist = mDNStrue;
- return mDNStrue;
- }
- else if (typeCovered == kDNSType_SOA)
- {
- LogInfo("IsResponseAcceptable: Accepting RRSIG %s matches SOA type (nseclist = 1)", CRDisplayString(m, newcr));
- *nseclist = mDNStrue;
- return mDNStrue;
- }
- else return mDNSfalse;
- }
- if (rr->rrtype == kDNSType_NSEC)
- {
- if (!UNICAST_NSEC(rr))
- {
- LogMsg("IsResponseAcceptable: ERROR!! Not a unicast NSEC %s", CRDisplayString(m, newcr));
- return mDNSfalse;
- }
- LogInfo("IsResponseAcceptable: Accepting NSEC %s (nseclist = 1)", CRDisplayString(m, newcr));
- *nseclist = mDNStrue;
- return mDNStrue;
- }
- if (rr->rrtype == kDNSType_SOA)
- {
- LogInfo("IsResponseAcceptable: Accepting SOA %s (nseclist = 1)", CRDisplayString(m, newcr));
- *nseclist = mDNStrue;
- return mDNStrue;
- }
- else if (rr->rrtype == kDNSType_NSEC3)
- {
- LogInfo("IsResponseAcceptable: Accepting NSEC3 %s (nseclist = 1)", CRDisplayString(m, newcr));
- *nseclist = mDNStrue;
- return mDNStrue;
- }
- }
return mDNSfalse;
}
-mDNSlocal void FreeNSECRecords(mDNS *const m, CacheRecord *NSECRecords)
-{
- CacheRecord *rp, *next;
-
- for (rp = NSECRecords; rp; rp = next)
- {
- next = rp->next;
- ReleaseCacheRecord(m, rp);
- }
-}
-
-// If we received zero DNSSEC records even when the DO/EDNS0 bit was set, we need to provide this
-// information to ValidatingResponse question to indicate the DNSSEC status to the application
-mDNSlocal void mDNSCoreReceiveNoDNSSECAnswers(mDNS *const m, const DNSMessage *const response, const mDNSu8 *end, const mDNSAddr *dstaddr,
- mDNSIPPort dstport, const mDNSInterfaceID InterfaceID)
-{
- int i;
- const mDNSu8 *ptr = response->data;
-
- for (i = 0; i < response->h.numQuestions && ptr && ptr < end; i++)
- {
- DNSQuestion pktq;
- DNSQuestion *qptr = mDNSNULL;
- ptr = getQuestion(response, ptr, end, InterfaceID, &pktq);
- if (ptr && (qptr = ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &pktq, !dstaddr, mDNSNULL)) &&
- qptr->ValidatingResponse)
- {
- DNSQuestion *next, *q;
-
- if (qptr->DuplicateOf)
- LogMsg("mDNSCoreReceiveNoDNSSECAnswers: ERROR!! qptr %##s (%s) Duplicate question matching response", qptr->qname.c, DNSTypeName(qptr->qtype));
-
- // Be careful to call the callback for duplicate questions first and then the original
- // question. If we called the callback on the original question, it could stop and
- // a duplicate question would become the original question.
- mDNS_DropLockBeforeCallback(); // Allow client (and us) to legally make mDNS API calls
- for (q = qptr->next ; q && q != m->NewQuestions; q = next)
- {
- next = q->next;
- if (q->DuplicateOf == qptr)
- {
- if (q->ValidatingResponse)
- LogInfo("mDNSCoreReceiveNoDNSSECAnswers: qptr %##s (%s) Duplicate question found", q->qname.c, DNSTypeName(q->qtype));
- else
- LogMsg("mDNSCoreReceiveNoDNSSECAnswers: ERROR!! qptr %##s (%s) Duplicate question not ValidatingResponse", q->qname.c, DNSTypeName(q->qtype));
- if (q->QuestionCallback)
- q->QuestionCallback(m, q, mDNSNULL, QC_nodnssec);
- }
- }
- if (qptr->QuestionCallback)
- qptr->QuestionCallback(m, qptr, mDNSNULL, QC_nodnssec);
- mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
- }
- }
-}
-
-mDNSlocal void mDNSCoreReceiveNoUnicastAnswers(mDNS *const m, const DNSMessage *const response, const mDNSu8 *end, const mDNSAddr *dstaddr,
- mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, uDNS_LLQType LLQType, mDNSu8 rcode, CacheRecord *NSECRecords)
+mDNSlocal void mDNSCoreReceiveNoUnicastAnswers(mDNS *const m, const DNSMessage *const response, const mDNSu8 *end,
+ const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID,
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ const mdns_querier_t querier, const mdns_dns_service_t uDNSService,
+#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+ denial_of_existence_records_t **denial_of_existence_records_ptr,
+#endif
+ const uDNS_LLQType LLQType)
{
int i;
const mDNSu8 *ptr = response->data;
@@ -8484,20 +8468,56 @@ mDNSlocal void mDNSCoreReceiveNoUnicastAnswers(mDNS *const m, const DNSMessage *
for (i = 0; i < response->h.numQuestions && ptr && ptr < end; i++)
{
DNSQuestion q;
- DNSQuestion *qptr = mDNSNULL;
ptr = getQuestion(response, ptr, end, InterfaceID, &q);
- if (ptr && (qptr = ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q, !dstaddr, mDNSNULL)))
+ if (ptr)
{
- CacheRecord *rr, *neg = mDNSNULL;
- CacheGroup *cg = CacheGroupForName(m, q.qnamehash, &q.qname);
- for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
- if (SameNameRecordAnswersQuestion(&rr->resrec, qptr))
+ DNSQuestion *qptr;
+ CacheRecord *cr, *neg = mDNSNULL;
+ CacheGroup *cg;
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ if (querier)
+ {
+ qptr = Querier_GetDNSQuestion(querier);
+ }
+ else
+#endif
+ {
+ qptr = ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q, !dstaddr);
+ if (!qptr)
+ {
+ continue;
+ }
+ }
+ cg = CacheGroupForName(m, q.qnamehash, &q.qname);
+ for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
+ {
+ mDNSBool isAnswer;
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ if (querier)
+ {
+ isAnswer = (cr->resrec.dnsservice == uDNSService) && Querier_SameNameCacheRecordIsAnswer(cr, querier);
+ }
+ else
+#endif
+ {
+ isAnswer = SameNameCacheRecordAnswersQuestion(cr, qptr);
+ }
+ if (isAnswer)
{
// 1. If we got a fresh answer to this query, then don't need to generate a negative entry
- if (RRExpireTime(rr) - m->timenow > 0) break;
+ if (RRExpireTime(cr) - m->timenow > 0) break;
// 2. If we already had a negative entry, keep track of it so we can resurrect it instead of creating a new one
- if (rr->resrec.RecordType == kDNSRecordTypePacketNegative) neg = rr;
+ if (cr->resrec.RecordType == kDNSRecordTypePacketNegative) neg = cr;
+ else if (cr->resrec.mortality == Mortality_Ghost)
+ {
+ // 3. If the existing entry is expired, mark it to be purged
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] mDNSCoreReceiveNoUnicastAnswers: Removing expired record" PRI_S,
+ q.request_id, mDNSVal16(q.TargetQID), CRDisplayString(m, cr));
+ mDNS_PurgeCacheResourceRecord(m, cr);
+ }
}
+ }
// When we're doing parallel unicast and multicast queries for dot-local names (for supporting Microsoft
// Active Directory sites) we don't want to waste memory making negative cache entries for all the unicast answers.
// Otherwise we just fill up our cache with negative entries for just about every single multicast name we ever look up
@@ -8516,26 +8536,34 @@ mDNSlocal void mDNSCoreReceiveNoUnicastAnswers(mDNS *const m, const DNSMessage *
// do the appropriate thing. This negative response is also needed for appending new search domains.
if (!InterfaceID && q.qtype != kDNSType_SOA && IsLocalDomain(&q.qname))
{
- if (!rr)
+ if (!cr)
{
- LogInfo("mDNSCoreReceiveNoUnicastAnswers: Generate negative response for %##s (%s)", q.qname.c, DNSTypeName(q.qtype));
- m->CurrentQuestion = qptr;
- // We are not creating a cache record in this case, we need to pass back
- // the error we got so that the proxy code can return the right one to
- // the application
- if (qptr->ProxyQuestion)
- qptr->responseFlags = response->h.flags;
- GenerateNegativeResponse(m, mDNSInterface_Any, QC_forceresponse);
- m->CurrentQuestion = mDNSNULL;
+ if (qptr)
+ {
+ const mDNSBool noData = ((response->h.flags.b[1] & kDNSFlag1_RC_Mask) == kDNSFlag1_RC_NoErr) ? mDNStrue : mDNSfalse;
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] mDNSCoreReceiveNoUnicastAnswers: Generate negative response for " PRI_DM_NAME " (" PUB_S ")",
+ q.request_id, mDNSVal16(q.TargetQID), DM_NAME_PARAM(&q.qname), DNSTypeName(q.qtype));
+ m->CurrentQuestion = qptr;
+ // We are not creating a cache record in this case, we need to pass back
+ // the error we got so that the proxy code can return the right one to
+ // the application
+ if (qptr->ProxyQuestion)
+ qptr->responseFlags = response->h.flags;
+ GenerateNegativeResponseEx(m, mDNSInterface_Any, QC_forceresponse, noData);
+ m->CurrentQuestion = mDNSNULL;
+ }
}
else
{
- LogInfo("mDNSCoreReceiveNoUnicastAnswers: Skipping check and not creating a negative cache entry for %##s (%s)", q.qname.c, DNSTypeName(q.qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] mDNSCoreReceiveNoUnicastAnswers: Skipping check and not creating a negative cache entry for " PRI_DM_NAME " (" PUB_S ")",
+ q.request_id, mDNSVal16(q.TargetQID), DM_NAME_PARAM(&q.qname), DNSTypeName(q.qtype));
}
}
else
{
- if (!rr)
+ if (!cr)
{
// We start off assuming a negative caching TTL of 60 seconds
// but then look to see if we can find an SOA authority record to tell us a better value we should be using
@@ -8579,7 +8607,7 @@ mDNSlocal void mDNSCoreReceiveNoUnicastAnswers(mDNS *const m, const DNSMessage *
//
// For ProxyQuestions, we don't do this as we need to create additional SOA records to cache them
// along with the negative cache record. For simplicity, we don't create the additional records.
- if (!qptr->ProxyQuestion && q.qtype == kDNSType_SOA)
+ if ((!qptr || !qptr->ProxyQuestion) && (q.qtype == kDNSType_SOA))
{
int qcount = CountLabels(&q.qname);
int scount = CountLabels(m->rec.r.resrec.name);
@@ -8610,29 +8638,27 @@ mDNSlocal void mDNSCoreReceiveNoUnicastAnswers(mDNS *const m, const DNSMessage *
// If we already had a negative cache entry just update it, else make one or more new negative cache entries.
if (neg)
{
- LogInfo("mDNSCoreReceiveNoUnicastAnswers: Renewing negative TTL from %d to %d %s", neg->resrec.rroriginalttl, negttl, CRDisplayString(m, neg));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] mDNSCoreReceiveNoUnicastAnswers: Renewing negative TTL from %d to %d " PRI_S,
+ q.request_id, mDNSVal16(q.TargetQID), neg->resrec.rroriginalttl, negttl, CRDisplayString(m, neg));
RefreshCacheRecord(m, neg, negttl);
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+ // replace the old records with the new ones
+ // If qptr is NULL, it means the question is no longer active, and we do not process the record
+ // for DNSSEC.
+ if ((qptr != mDNSNULL) && qptr->DNSSECStatus.enable_dnssec)
+ {
+ update_denial_records_in_cache_record(neg, denial_of_existence_records_ptr);
+ }
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
// When we created the cache for the first time and answered the question, the question's
// interval was set to MaxQuestionInterval. If the cache is about to expire and we are resending
// the queries, the interval should still be at MaxQuestionInterval. If the query is being
// restarted (setting it to InitialQuestionInterval) for other reasons e.g., wakeup,
// we should reset its question interval here to MaxQuestionInterval.
- ResetQuestionState(m, qptr);
- if (DNSSECQuestion(qptr))
- neg->CRDNSSECQuestion = 1;
- // Update the NSEC records again.
- // TBD: Need to purge and revalidate if the cached NSECS and the new set are not same.
- if (NSECRecords)
+ if (qptr)
{
- if (!AddNSECSForCacheRecord(m, NSECRecords, neg, rcode))
- {
- // We might just have an SOA record for zones that are not signed and hence don't log
- // this as an error
- LogInfo("mDNSCoreReceiveNoUnicastAnswers: AddNSECSForCacheRecord failed to add NSEC for negcr %s during refresh", CRDisplayString(m, neg));
- FreeNSECRecords(m, NSECRecords);
- neg->CRDNSSECQuestion = 0;
- }
- NSECRecords = mDNSNULL;
+ ResetQuestionState(m, qptr);
}
if (SOARecord)
{
@@ -8646,7 +8672,11 @@ mDNSlocal void mDNSCoreReceiveNoUnicastAnswers(mDNS *const m, const DNSMessage *
{
CacheRecord *negcr;
debugf("mDNSCoreReceiveNoUnicastAnswers making negative cache entry TTL %d for %##s (%s)", negttl, name->c, DNSTypeName(q.qtype));
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ MakeNegativeCacheRecord(m, &m->rec.r, name, hash, q.qtype, q.qclass, negttl, mDNSInterface_Any, uDNSService);
+#else
MakeNegativeCacheRecord(m, &m->rec.r, name, hash, q.qtype, q.qclass, negttl, mDNSInterface_Any, qptr->qDNSServer);
+#endif
m->rec.r.responseFlags = response->h.flags;
// We create SOA records above which might create new cache groups. Earlier
// in the function we looked up the cache group for the name and it could have
@@ -8654,52 +8684,29 @@ mDNSlocal void mDNSCoreReceiveNoUnicastAnswers(mDNS *const m, const DNSMessage *
// it will create additional cache groups for the same name. To avoid that,
// look up the cache group again to re-initialize cg again.
cg = CacheGroupForName(m, hash, name);
- if (NSECRecords && DNSSECQuestion(qptr))
+ // Need to add with a delay so that we can tag the SOA record
+ negcr = CreateNewCacheEntry(m, HashSlotFromNameHash(hash), cg, 1, mDNStrue, mDNSNULL);
+
+ if (negcr)
{
- // Create the cache entry with delay and then add the NSEC records
- // to it and add it immediately.
- negcr = CreateNewCacheEntry(m, HashSlotFromNameHash(hash), cg, 1, mDNStrue, mDNSNULL);
- if (negcr)
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+ // If qptr is NULL, it means the question is no longer active, and we do not process the
+ // record for DNSSEC.
+ if (qptr != mDNSNULL && qptr->DNSSECStatus.enable_dnssec)
{
- negcr->CRDNSSECQuestion = 0;
- if (!AddNSECSForCacheRecord(m, NSECRecords, negcr, rcode))
- {
- LogInfo("mDNSCoreReceiveNoUnicastAnswers: AddNSECSForCacheRecord failed to add NSEC for negcr %s",
- CRDisplayString(m, negcr));
- FreeNSECRecords(m, NSECRecords);
- }
- else
- {
- negcr->CRDNSSECQuestion = 1;
- LogInfo("mDNSCoreReceiveNoUnicastAnswers: AddNSECSForCacheRecord added neg NSEC for %s", CRDisplayString(m, negcr));
- }
- NSECRecords = mDNSNULL;
- negcr->DelayDelivery = 0;
- CacheRecordDeferredAdd(m, negcr);
+ update_denial_records_in_cache_record(negcr, denial_of_existence_records_ptr);
}
- m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
- break;
- }
- else
- {
- // Need to add with a delay so that we can tag the SOA record
- negcr = CreateNewCacheEntry(m, HashSlotFromNameHash(hash), cg, 1, mDNStrue, mDNSNULL);
- if (negcr)
- {
- negcr->CRDNSSECQuestion = 0;
- if (DNSSECQuestion(qptr))
- negcr->CRDNSSECQuestion = 1;
- negcr->DelayDelivery = 0;
+#endif
+ negcr->DelayDelivery = 0;
- if (SOARecord)
- {
- if (negcr->soa)
- ReleaseCacheRecord(m, negcr->soa);
- negcr->soa = SOARecord;
- SOARecord = mDNSNULL;
- }
- CacheRecordDeferredAdd(m, negcr);
+ if (SOARecord)
+ {
+ if (negcr->soa)
+ ReleaseCacheRecord(m, negcr->soa);
+ negcr->soa = SOARecord;
+ SOARecord = mDNSNULL;
}
+ CacheRecordDeferredAdd(m, negcr);
}
m->rec.r.responseFlags = zeroID;
m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
@@ -8712,13 +8719,17 @@ mDNSlocal void mDNSCoreReceiveNoUnicastAnswers(mDNS *const m, const DNSMessage *
}
}
}
- if (NSECRecords) { LogInfo("mDNSCoreReceiveNoUnicastAnswers: NSECRecords not used"); FreeNSECRecords(m, NSECRecords); }
- if (SOARecord) { LogInfo("mDNSCoreReceiveNoUnicastAnswers: SOARecord not used"); ReleaseCacheRecord(m, SOARecord); }
+ if (SOARecord)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "mDNSCoreReceiveNoUnicastAnswers: SOARecord not used");
+ ReleaseCacheRecord(m, SOARecord);
+ }
}
mDNSlocal void mDNSCorePrintStoredProxyRecords(mDNS *const m)
{
AuthRecord *rrPtr = mDNSNULL;
+ if (!m->SPSRRSet) return;
LogSPS("Stored Proxy records :");
for (rrPtr = m->SPSRRSet; rrPtr; rrPtr = rrPtr->next)
{
@@ -8742,222 +8753,170 @@ mDNSlocal mDNSBool mDNSCoreRegisteredProxyRecord(mDNS *const m, AuthRecord *rr)
return mDNSfalse;
}
-mDNSlocal CacheRecord* mDNSCoreReceiveCacheCheck(mDNS *const m, const DNSMessage *const response, uDNS_LLQType LLQType,
- const mDNSu32 slot, CacheGroup *cg, DNSQuestion *unicastQuestion, CacheRecord ***cfp, CacheRecord **NSECCachePtr,
- mDNSInterfaceID InterfaceID)
+mDNSexport CacheRecord* mDNSCoreReceiveCacheCheck(mDNS *const m, const DNSMessage *const response, uDNS_LLQType LLQType,
+ const mDNSu32 slot, CacheGroup *cg, CacheRecord ***cfp, mDNSInterfaceID InterfaceID)
{
- CacheRecord *rr;
+ CacheRecord *cr;
CacheRecord **cflocal = *cfp;
- for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
+ for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
{
mDNSBool match;
// Resource record received via unicast, the resGroupID should match ?
if (!InterfaceID)
{
- mDNSu16 id1 = (rr->resrec.rDNSServer ? rr->resrec.rDNSServer->resGroupID : 0);
- mDNSu16 id2 = (m->rec.r.resrec.rDNSServer ? m->rec.r.resrec.rDNSServer->resGroupID : 0);
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ match = (cr->resrec.dnsservice == m->rec.r.resrec.dnsservice) ? mDNStrue : mDNSfalse;
+#else
+ const mDNSu32 id1 = (cr->resrec.rDNSServer ? cr->resrec.rDNSServer->resGroupID : 0);
+ const mDNSu32 id2 = (m->rec.r.resrec.rDNSServer ? m->rec.r.resrec.rDNSServer->resGroupID : 0);
match = (id1 == id2);
+#endif
}
else
- match = (rr->resrec.InterfaceID == InterfaceID);
+ match = (cr->resrec.InterfaceID == InterfaceID);
// If we found this exact resource record, refresh its TTL
- if (match && IdenticalSameNameRecord(&m->rec.r.resrec, &rr->resrec))
+ if (match)
{
- if (m->rec.r.resrec.rdlength > InlineCacheRDSize)
- verbosedebugf("mDNSCoreReceiveCacheCheck: Found record size %5d interface %p already in cache: %s",
- m->rec.r.resrec.rdlength, InterfaceID, CRDisplayString(m, &m->rec.r));
-
- if (m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask)
+ if (IdenticalSameNameRecord(&m->rec.r.resrec, &cr->resrec))
{
- // If this packet record has the kDNSClass_UniqueRRSet flag set, then add it to our cache flushing list
- if (rr->NextInCFList == mDNSNULL && *cfp != &rr->NextInCFList && LLQType != uDNS_LLQ_Events)
+ if (m->rec.r.resrec.rdlength > InlineCacheRDSize)
+ verbosedebugf("mDNSCoreReceiveCacheCheck: Found record size %5d interface %p already in cache: %s",
+ m->rec.r.resrec.rdlength, InterfaceID, CRDisplayString(m, &m->rec.r));
+
+ if (m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask)
{
- *cflocal = rr;
- cflocal = &rr->NextInCFList;
- *cflocal = (CacheRecord*)1;
- *cfp = &rr->NextInCFList;
+ // If this packet record has the kDNSClass_UniqueRRSet flag set, then add it to our cache flushing list
+ if (cr->NextInCFList == mDNSNULL && *cfp != &cr->NextInCFList && LLQType != uDNS_LLQ_Events)
+ {
+ *cflocal = cr;
+ cflocal = &cr->NextInCFList;
+ *cflocal = (CacheRecord*)1;
+ *cfp = &cr->NextInCFList;
+ }
+
+ // If this packet record is marked unique, and our previous cached copy was not, then fix it
+ if (!(cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask))
+ {
+ DNSQuestion *q;
+ for (q = m->Questions; q; q=q->next)
+ {
+ if (CacheRecordAnswersQuestion(cr, q))
+ q->UniqueAnswers++;
+ }
+ cr->resrec.RecordType = m->rec.r.resrec.RecordType;
+ }
}
- // If this packet record is marked unique, and our previous cached copy was not, then fix it
- if (!(rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask))
+ if (!SameRDataBody(&m->rec.r.resrec, &cr->resrec.rdata->u, SameDomainNameCS))
+ {
+ // If the rdata of the packet record differs in name capitalization from the record in our cache
+ // then mDNSPlatformMemSame will detect this. In this case, throw the old record away, so that clients get
+ // a 'remove' event for the record with the old capitalization, and then an 'add' event for the new one.
+ // <rdar://problem/4015377> mDNS -F returns the same domain multiple times with different casing
+ cr->resrec.rroriginalttl = 0;
+ cr->TimeRcvd = m->timenow;
+ cr->UnansweredQueries = MaxUnansweredQueries;
+ SetNextCacheCheckTimeForRecord(m, cr);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "mDNSCoreReceiveCacheCheck: Discarding due to domainname case change old: " PRI_S, CRDisplayString(m, cr));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "mDNSCoreReceiveCacheCheck: Discarding due to domainname case change new: " PRI_S, CRDisplayString(m, &m->rec.r));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "mDNSCoreReceiveCacheCheck: Discarding due to domainname case change in %d slot %3d in %d %d",
+ NextCacheCheckEvent(cr) - m->timenow, slot, m->rrcache_nextcheck[slot] - m->timenow, m->NextCacheCheck - m->timenow);
+ // DO NOT break out here -- we want to continue as if we never found it
+ }
+ else if (m->rec.r.resrec.rroriginalttl > 0)
{
DNSQuestion *q;
- for (q = m->Questions; q; q=q->next)
+
+ m->mDNSStats.CacheRefreshed++;
+
+ if ((cr->resrec.mortality == Mortality_Ghost) && !cr->DelayDelivery)
{
- if (ResourceRecordAnswersQuestion(&rr->resrec, q))
- q->UniqueAnswers++;
+ cr->DelayDelivery = NonZeroTime(m->timenow);
+ debugf("mDNSCoreReceiveCacheCheck: Reset DelayDelivery for mortalityExpired EXP:%d RR %s", m->timenow - RRExpireTime(cr), CRDisplayString(m, cr));
}
- rr->resrec.RecordType = m->rec.r.resrec.RecordType;
- }
- }
-
- if (!SameRDataBody(&m->rec.r.resrec, &rr->resrec.rdata->u, SameDomainNameCS))
- {
- // If the rdata of the packet record differs in name capitalization from the record in our cache
- // then mDNSPlatformMemSame will detect this. In this case, throw the old record away, so that clients get
- // a 'remove' event for the record with the old capitalization, and then an 'add' event for the new one.
- // <rdar://problem/4015377> mDNS -F returns the same domain multiple times with different casing
- rr->resrec.rroriginalttl = 0;
- rr->TimeRcvd = m->timenow;
- rr->UnansweredQueries = MaxUnansweredQueries;
- SetNextCacheCheckTimeForRecord(m, rr);
- LogInfo("mDNSCoreReceiveCacheCheck: Discarding due to domainname case change old: %s", CRDisplayString(m, rr));
- LogInfo("mDNSCoreReceiveCacheCheck: Discarding due to domainname case change new: %s", CRDisplayString(m, &m->rec.r));
- LogInfo("mDNSCoreReceiveCacheCheck: Discarding due to domainname case change in %d slot %3d in %d %d",
- NextCacheCheckEvent(rr) - m->timenow, slot, m->rrcache_nextcheck[slot] - m->timenow, m->NextCacheCheck - m->timenow);
- // DO NOT break out here -- we want to continue as if we never found it
- }
- else if (!IdenticalAnonInfo(m->rec.r.resrec.AnonInfo, rr->resrec.AnonInfo))
- {
- // If the NSEC3 record changed, a few possibilities
- //
- // 1) the peer reinitialized e.g., after network change and still part of the
- // same set.
- // 2) the peer went to a different set but we did not see the goodbyes. If we just
- // update the nsec3 record, it would be incorrect. Flush the cache so that we
- // can deliver a RMV followed by ADD.
- // 3) if the peer is ourselves and we see the goodbye when moving to a different set
- // and so we flush the cache and create a new cache record with the new set information.
- // Now we move back to the original set. In this case, we can't just update the
- // NSEC3 record alone. We need to flush so that we can deliver an RMV followed by ADD
- // when we create the new cache entry.
- //
- // Note: For case (1), we could avoid flushing the cache but we can't tell the difference
- // from the other cases.
- rr->resrec.rroriginalttl = 0;
- rr->TimeRcvd = m->timenow;
- rr->UnansweredQueries = MaxUnansweredQueries;
- SetNextCacheCheckTimeForRecord(m, rr);
- LogInfo("mDNSCoreReceiveCacheCheck: AnonInfo changed for %s", CRDisplayString(m, rr));
- // DO NOT break out here -- we want to continue as if we never found it. When we return
- // from this function, we will create a new cache entry with the new NSEC3 record
- }
- else if (m->rec.r.resrec.rroriginalttl > 0)
- {
- DNSQuestion *q;
- m->mDNSStats.CacheRefreshed++;
-
- if (rr->resrec.mortality == Mortality_Ghost && unicastQuestion && (unicastQuestion->allowExpired != AllowExpired_AllowExpiredAnswers) && !rr->DelayDelivery)
- {
- rr->DelayDelivery = NonZeroTime(m->timenow);
- debugf("mDNSCoreReceiveCacheCheck: Reset DelayDelivery for mortalityExpired EXP:%d RR %s", m->timenow - RRExpireTime(rr), CRDisplayString(m, rr));
- }
-
- if (rr->resrec.rroriginalttl == 0) debugf("uDNS rescuing %s", CRDisplayString(m, rr));
- RefreshCacheRecord(m, rr, m->rec.r.resrec.rroriginalttl);
- rr->responseFlags = response->h.flags;
-
- // If we may have NSEC records returned with the answer (which we don't know yet as it
- // has not been processed), we need to cache them along with the first cache
- // record in the list that answers the question so that it can be used for validation
- // later. The "type" check below is to make sure that we cache on the cache record
- // that would answer the question. It is possible that we might cache additional things
- // e.g., MX question might cache A records also, and we want to cache the NSEC on
- // the record that answers the question.
- if (response->h.numAnswers && unicastQuestion && unicastQuestion->qtype == rr->resrec.rrtype
- && !(*NSECCachePtr))
- {
- LogInfo("mDNSCoreReceiveCacheCheck: rescuing RR %s", CRDisplayString(m, rr));
- *NSECCachePtr = rr;
- }
- // We have to reset the question interval to MaxQuestionInterval so that we don't keep
- // polling the network once we get a valid response back. For the first time when a new
- // cache entry is created, AnswerCurrentQuestionWithResourceRecord does that.
- // Subsequently, if we reissue questions from within the mDNSResponder e.g., DNS server
- // configuration changed, without flushing the cache, we reset the question interval here.
- // Currently, we do this for for both multicast and unicast questions as long as the record
- // type is unique. For unicast, resource record is always unique and for multicast it is
- // true for records like A etc. but not for PTR.
- if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask)
- {
- for (q = m->Questions; q; q=q->next)
+ if (cr->resrec.rroriginalttl == 0) debugf("uDNS rescuing %s", CRDisplayString(m, cr));
+ RefreshCacheRecord(m, cr, m->rec.r.resrec.rroriginalttl);
+ // RefreshCacheRecordCacheGroupOrder will modify the cache group member list that is currently being iterated over in this for-loop.
+ // It is safe to call because the else-if body will unconditionally break out of the for-loop now that it has found the entry to update.
+ RefreshCacheRecordCacheGroupOrder(cg, cr);
+ cr->responseFlags = response->h.flags;
+
+ // If we may have NSEC records returned with the answer (which we don't know yet as it
+ // has not been processed), we need to cache them along with the first cache
+ // record in the list that answers the question so that it can be used for validation
+ // later. The "type" check below is to make sure that we cache on the cache record
+ // that would answer the question. It is possible that we might cache additional things
+ // e.g., MX question might cache A records also, and we want to cache the NSEC on
+ // the record that answers the question.
+ if (!InterfaceID)
{
- if (!q->DuplicateOf && !q->LongLived &&
- ActiveQuestion(q) && ResourceRecordAnswersQuestion(&rr->resrec, q))
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "mDNSCoreReceiveCacheCheck: rescuing RR " PRI_S, CRDisplayString(m, cr));
+ }
+ // We have to reset the question interval to MaxQuestionInterval so that we don't keep
+ // polling the network once we get a valid response back. For the first time when a new
+ // cache entry is created, AnswerCurrentQuestionWithResourceRecord does that.
+ // Subsequently, if we reissue questions from within the mDNSResponder e.g., DNS server
+ // configuration changed, without flushing the cache, we reset the question interval here.
+ // Currently, we do this for for both multicast and unicast questions as long as the record
+ // type is unique. For unicast, resource record is always unique and for multicast it is
+ // true for records like A etc. but not for PTR.
+ if (cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask)
+ {
+ for (q = m->Questions; q; q=q->next)
{
- ResetQuestionState(m, q);
- debugf("mDNSCoreReceiveCacheCheck: Set MaxQuestionInterval for %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
- break; // Why break here? Aren't there other questions we might want to look at?-- SC July 2010
+ if (!q->DuplicateOf && !q->LongLived &&
+ ActiveQuestion(q) && CacheRecordAnswersQuestion(cr, q))
+ {
+ ResetQuestionState(m, q);
+ debugf("mDNSCoreReceiveCacheCheck: Set MaxQuestionInterval for %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
+ break; // Why break here? Aren't there other questions we might want to look at?-- SC July 2010
+ }
}
}
+ break; // Check usage of RefreshCacheRecordCacheGroupOrder before removing (See note above)
+ }
+ else
+ {
+ // If the packet TTL is zero, that means we're deleting this record.
+ // To give other hosts on the network a chance to protest, we push the deletion
+ // out one second into the future. Also, we set UnansweredQueries to MaxUnansweredQueries.
+ // Otherwise, we'll do final queries for this record at 80% and 90% of its apparent
+ // lifetime (800ms and 900ms from now) which is a pointless waste of network bandwidth.
+ // If record's current expiry time is more than a second from now, we set it to expire in one second.
+ // If the record is already going to expire in less than one second anyway, we leave it alone --
+ // we don't want to let the goodbye packet *extend* the record's lifetime in our cache.
+ debugf("DE for %s", CRDisplayString(m, cr));
+ if (RRExpireTime(cr) - m->timenow > mDNSPlatformOneSecond)
+ {
+ cr->resrec.rroriginalttl = 1;
+ cr->TimeRcvd = m->timenow;
+ cr->UnansweredQueries = MaxUnansweredQueries;
+ SetNextCacheCheckTimeForRecord(m, cr);
+ }
+ break;
}
- break;
}
- else
+ else if (cr->resrec.rroriginalttl != 0 && // Not already marked for discarding
+ m->rec.r.resrec.rrclass == cr->resrec.rrclass &&
+ (m->rec.r.resrec.rrtype != cr->resrec.rrtype &&
+ (m->rec.r.resrec.rrtype == kDNSType_CNAME || cr->resrec.rrtype == kDNSType_CNAME)))
{
- // If the packet TTL is zero, that means we're deleting this record.
- // To give other hosts on the network a chance to protest, we push the deletion
- // out one second into the future. Also, we set UnansweredQueries to MaxUnansweredQueries.
- // Otherwise, we'll do final queries for this record at 80% and 90% of its apparent
- // lifetime (800ms and 900ms from now) which is a pointless waste of network bandwidth.
- // If record's current expiry time is more than a second from now, we set it to expire in one second.
- // If the record is already going to expire in less than one second anyway, we leave it alone --
- // we don't want to let the goodbye packet *extend* the record's lifetime in our cache.
- debugf("DE for %s", CRDisplayString(m, rr));
- if (RRExpireTime(rr) - m->timenow > mDNSPlatformOneSecond)
- {
- rr->resrec.rroriginalttl = 1;
- rr->TimeRcvd = m->timenow;
- rr->UnansweredQueries = MaxUnansweredQueries;
- SetNextCacheCheckTimeForRecord(m, rr);
- }
- break;
+ // If the cache record rrtype doesn't match and one is a CNAME, then flush this record
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "mDNSCoreReceiveCacheCheck: Discarding (%s) " PRI_S " rrtype change from (%s) to (%s)",
+ MortalityDisplayString(cr->resrec.mortality), CRDisplayString(m, cr), DNSTypeName(cr->resrec.rrtype), DNSTypeName(m->rec.r.resrec.rrtype));
+ mDNS_PurgeCacheResourceRecord(m, cr);
+ // DO NOT break out here -- we want to continue iterating the cache entries
}
}
}
- return rr;
-}
-
-mDNSlocal void mDNSParseNSEC3Records(mDNS *const m, const DNSMessage *const response, const mDNSu8 *end,
- const mDNSInterfaceID InterfaceID, CacheRecord **NSEC3Records)
-{
- const mDNSu8 *ptr;
- CacheRecord *rr;
- int i;
-
- if (!response->h.numAuthorities)
- return;
- ptr = LocateAuthorities(response, end);
- if (!ptr)
- {
- LogInfo("mDNSParseNSEC3Records: ERROR can't locate authorities");
- return;
- }
- for (i = 0; i < response->h.numAuthorities && ptr && ptr < end; i++)
- {
- CacheGroup *cg;
-
- ptr = GetLargeResourceRecord(m, response, ptr, end, InterfaceID, kDNSRecordTypePacketAuth, &m->rec);
- if (!ptr || m->rec.r.resrec.RecordType == kDNSRecordTypePacketNegative || m->rec.r.resrec.rrtype != kDNSType_NSEC3)
- {
- debugf("mDNSParseNSEC3Records: ptr %p, Record %s, ignoring", ptr, CRDisplayString(m, &m->rec.r));
- m->rec.r.resrec.RecordType = 0;
- continue;
- }
- cg = CacheGroupForRecord(m, &m->rec.r.resrec);
- // Create the cache entry but don't add it to the cache it. We need
- // to cache this along with the main cache record.
- rr = CreateNewCacheEntry(m, HashSlotFromNameHash(m->rec.r.resrec.namehash), cg, 0, mDNSfalse, mDNSNULL);
- if (rr)
- {
- debugf("mDNSParseNSEC3Records: %s", CRDisplayString(m, rr));
- *NSEC3Records = rr;
- NSEC3Records = &rr->next;
- }
- m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
- }
+ return cr;
}
mDNSlocal void mDNSCoreResetRecord(mDNS *const m)
{
m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
- if (m->rec.r.resrec.AnonInfo)
- {
- FreeAnonInfo(m->rec.r.resrec.AnonInfo);
- m->rec.r.resrec.AnonInfo = mDNSNULL;
- }
}
// Note: mDNSCoreReceiveResponse calls mDNS_Deregister_internal which can call a user callback, which may change
@@ -8966,16 +8925,17 @@ mDNSlocal void mDNSCoreResetRecord(mDNS *const m)
// InterfaceID non-NULL tells us the interface this multicast response was received on
// InterfaceID NULL tells us this was a unicast response
// dstaddr NULL tells us we received this over an outgoing TCP connection we made
-mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
- const DNSMessage *const response, const mDNSu8 *end,
- const mDNSAddr *srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport,
- const mDNSInterfaceID InterfaceID)
+mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, const DNSMessage *const response, const mDNSu8 *end,
+ const mDNSAddr *srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport,
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ mdns_querier_t querier, mdns_dns_service_t uDNSService,
+#endif
+ const mDNSInterfaceID InterfaceID)
{
int i;
- mDNSBool ResponseMCast = dstaddr && mDNSAddrIsDNSMulticast(dstaddr);
- mDNSBool ResponseSrcLocal = !srcaddr || mDNS_AddressIsLocalSubnet(m, InterfaceID, srcaddr);
+ const mDNSBool ResponseMCast = dstaddr && mDNSAddrIsDNSMulticast(dstaddr);
+ const mDNSBool ResponseSrcLocal = !srcaddr || mDNS_AddressIsLocalSubnet(m, InterfaceID, srcaddr);
DNSQuestion *llqMatch = mDNSNULL;
- DNSQuestion *unicastQuestion = mDNSNULL;
uDNS_LLQType LLQType = uDNS_recvLLQResponse(m, response, end, srcaddr, srcport, &llqMatch);
// "(CacheRecord*)1" is a special (non-zero) end-of-list marker
@@ -8983,14 +8943,6 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
// set non-zero, and that tells GetCacheEntity() that they're not, at this moment, eligible for recycling.
CacheRecord *CacheFlushRecords = (CacheRecord*)1;
CacheRecord **cfp = &CacheFlushRecords;
- CacheRecord *NSECRecords = mDNSNULL;
- CacheRecord *NSECCachePtr = mDNSNULL;
- CacheRecord **nsecp = &NSECRecords;
- CacheRecord *McastNSEC3Records = mDNSNULL;
- mDNSBool nseclist;
- mDNSu8 rcode = '\0';
- mDNSBool rrsigsCreated = mDNSfalse;
- mDNSBool DNSSECQuestion = mDNSfalse;
NetworkInterfaceInfo *llintf = FirstIPv4LLInterfaceForID(m, InterfaceID);
mDNSBool recordAcceptedInResponse = mDNSfalse; // Set if a record is accepted from a unicast mDNS response that answers an existing question.
@@ -9001,7 +8953,23 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
int firstadditional = firstauthority + response->h.numAuthorities;
int totalrecords = firstadditional + response->h.numAdditionals;
const mDNSu8 *ptr = response->data;
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
DNSServer *uDNSServer = mDNSNULL;
+#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+ denial_of_existence_records_t *denial_of_existence_records = mDNSNULL;
+ mDNSBool not_answer_but_required_for_dnssec = mDNSfalse;
+#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ // Determine whether the response is mDNS, as opposed to DNS.
+ // Thus far, the code has assumed that responses with IDs set to zero are mDNS responses. However, this condition
+ // isn't sufficient because queriers, which are used exclusively for DNS queries, may set the IDs of their queries
+ // to zero. And consequently, their responses may have their IDs set to zero. Specifically, zero-valued IDs are used
+ // for DNS over HTTPs, as specified by <https://tools.ietf.org/html/rfc8484#section-4.1>.
+ const mDNSBool ResponseIsMDNS = mDNSOpaque16IsZero(response->h.id) && !querier;
+#else
+ const mDNSBool ResponseIsMDNS = mDNSOpaque16IsZero(response->h.id);
+#endif
debugf("Received Response from %#-15a addressed to %#-15a on %p with "
"%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s %d bytes LLQType %d",
@@ -9011,7 +8979,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
response->h.numAuthorities, response->h.numAuthorities == 1 ? "y, " : "ies,",
response->h.numAdditionals, response->h.numAdditionals == 1 ? " " : "s", end - response->data, LLQType);
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS) && !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
if (mDNSSameIPPort(srcport, UnicastDNSPort))
{
MetricsUpdateDNSResponseSize((mDNSu32)(end - (mDNSu8 *)response));
@@ -9040,7 +9008,11 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
// should start at the end of the response and work forward in the
// datagram. Thus if there is any data for the authority section, the
// answer section is guaranteed to be unique.
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ if (!InterfaceID && (response->h.flags.b[0] & kDNSFlag0_TC) && !querier &&
+#else
if (!InterfaceID && (response->h.flags.b[0] & kDNSFlag0_TC) &&
+#endif
((response->h.numAnswers == 0) || ((response->h.numAuthorities == 0) && (response->h.numAdditionals == 0)))) return;
if (LLQType == uDNS_LLQ_Ignore) return;
@@ -9055,9 +9027,23 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
else
{
mDNSBool failure, returnEarly;
- rcode = (mDNSu8)(response->h.flags.b[1] & kDNSFlag1_RC_Mask);
+ const int rcode = response->h.flags.b[1] & kDNSFlag1_RC_Mask;
failure = !(rcode == kDNSFlag1_RC_NoErr || rcode == kDNSFlag1_RC_NXDomain || rcode == kDNSFlag1_RC_NotAuth);
returnEarly = mDNSfalse;
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ // When the QUERIER functionality is enabled, DNS transport is handled exclusively by querier objects. If this
+ // response was provided by a querier, but the RCODE is considered a failure, then set failure to false so that
+ // we don't return early. The logic of returning early was so that uDNS_CheckCurrentQuestion() could handle
+ // resending the query and generate a negative cache record if all servers were tried. If the querier provides a
+ // response, then it's the best response that it could provide. If the RCODE is considered a failure,
+ // mDNSCoreReceiveResponse() needs to create negative cache entries for the unanwered question, so totalrecords
+ // is set to 0 to ignore any records that the response may contain.
+ if (querier && failure)
+ {
+ totalrecords = 0;
+ failure = mDNSfalse;
+ }
+#endif
// We could possibly combine this with the similar loop at the end of this function --
// instead of tagging cache records here and then rescuing them if we find them in the answer section,
// we could instead use the "m->PktNum" mechanism to tag each cache record with the packet number in
@@ -9066,110 +9052,94 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
// packet number, then we deduce they are old and delete them
for (i = 0; i < response->h.numQuestions && ptr && ptr < end; i++)
{
- DNSQuestion q, *qptr = mDNSNULL, *suspiciousForQ = mDNSNULL;
+ DNSQuestion q;
+ DNSQuestion *qptr;
+ mDNSBool expectingResponse;
ptr = getQuestion(response, ptr, end, InterfaceID, &q);
- if (ptr && (qptr = ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q, !dstaddr, &suspiciousForQ)))
+ if (!ptr)
+ {
+ continue;
+ }
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ if (querier)
{
- if (!failure)
+ expectingResponse = mDNStrue;
+ qptr = mDNSNULL;
+ }
+ else
+#endif
+ {
+ qptr = ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q, !dstaddr);
+ expectingResponse = qptr ? mDNStrue : mDNSfalse;
+ }
+ if (!expectingResponse)
+ {
+ continue;
+ }
+ if (!failure)
+ {
+ CacheRecord *cr;
+ CacheGroup *cg = CacheGroupForName(m, q.qnamehash, &q.qname);
+ for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
{
- CacheRecord *rr;
- // Remember the unicast question that we found, which we use to make caching
- // decisions later on in this function
- CacheGroup *cg = CacheGroupForName(m, q.qnamehash, &q.qname);
- if (!mDNSOpaque16IsZero(response->h.id))
+ mDNSBool isAnswer;
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ if (querier)
{
- unicastQuestion = qptr;
- if (qptr->qDNSServer && DNSSECQuestion(qptr))
- {
- LogInfo("mDNSCoreReceiveResponse: Setting aware for %##s (%s) on %#a", qptr->qname.c,
- DNSTypeName(qptr->qtype), &qptr->qDNSServer->addr);
- qptr->qDNSServer->DNSSECAware = mDNStrue;
- qptr->qDNSServer->req_DO = mDNStrue;
- }
- if (qptr->ValidatingResponse)
- DNSSECQuestion = mDNStrue;
+ isAnswer = (cr->resrec.dnsservice == uDNSService) && Querier_SameNameCacheRecordIsAnswer(cr, querier);
}
- for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
- if (SameNameRecordAnswersQuestion(&rr->resrec, qptr))
- {
- debugf("uDNS marking %p %##s (%s) %p %s", q.InterfaceID, q.qname.c, DNSTypeName(q.qtype),
- rr->resrec.InterfaceID, CRDisplayString(m, rr));
- // Don't want to disturb rroriginalttl here, because code below might need it for the exponential backoff doubling algorithm
- rr->TimeRcvd = m->timenow - TicksTTL(rr) - 1;
- rr->UnansweredQueries = MaxUnansweredQueries;
- rr->CRDNSSECQuestion = 0;
- if (unicastQuestion && DNSSECQuestion(unicastQuestion))
- {
- LogInfo("mDNSCoreReceiveResponse: CRDNSSECQuestion set for record %s, question %##s (%s)", CRDisplayString(m, rr),
- unicastQuestion->qname.c, DNSTypeName(unicastQuestion->qtype));
- rr->CRDNSSECQuestion = 1;
- }
- }
- }
- else
- {
- if (qptr)
+ else
+#endif
{
- // If we recv any error from the DNSServer for a DNSSEC Query and if we know that the server
- // is not DNSSEC aware, stop doing DNSSEC for that DNSServer. Note that by setting the
- // req_DO to false here, the next retransmission for this question will turn off validation
- // and hence retransmit without the EDNS0/DOK option.
- if (DNSSECOptionalQuestion(qptr) && qptr->qDNSServer && !qptr->qDNSServer->DNSSECAware)
- {
- LogInfo("mDNSCoreReceiveResponse: Server %p responded with code %d to DNSSEC Query %##s (%s), clear DO flag",
- qptr->qDNSServer, rcode, q.qname.c, DNSTypeName(q.qtype));
- qptr->qDNSServer->req_DO = mDNSfalse;
- }
- // For Unicast DNS Queries, penalize the DNSServer
- else
- {
- LogInfo("mDNSCoreReceiveResponse: Server %p responded with code %d to query %##s (%s)",
- qptr->qDNSServer, rcode, q.qname.c, DNSTypeName(q.qtype));
- PenalizeDNSServer(m, qptr, response->h.flags);
- }
+ isAnswer = SameNameCacheRecordAnswersQuestion(cr, qptr);
+ }
+ if (isAnswer)
+ {
+ debugf("uDNS marking %p %##s (%s) %p %s", q.InterfaceID, q.qname.c, DNSTypeName(q.qtype),
+ cr->resrec.InterfaceID, CRDisplayString(m, cr));
+ // Don't want to disturb rroriginalttl here, because code below might need it for the exponential backoff doubling algorithm
+ cr->TimeRcvd = m->timenow - TicksTTL(cr) - 1;
+ cr->UnansweredQueries = MaxUnansweredQueries;
}
- returnEarly = mDNStrue;
}
}
- else if (!InterfaceID && suspiciousForQ)
+ else
{
- // If a response is suspicious for a question, then reissue the question via TCP
- LogInfo("mDNSCoreReceiveResponse: Server %p responded suspiciously to query %##s (%s) qID %d != rID: %d",
- suspiciousForQ->qDNSServer, q.qname.c, DNSTypeName(q.qtype),
- mDNSVal16(suspiciousForQ->TargetQID), mDNSVal16(response->h.id));
- uDNS_RestartQuestionAsTCP(m, suspiciousForQ, srcaddr, srcport);
- return;
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d->Q%d] mDNSCoreReceiveResponse: Server %p responded with code %d to query " PRI_DM_NAME " (" PUB_S ")",
+ qptr->request_id, mDNSVal16(qptr->TargetQID), qptr->qDNSServer, rcode,
+ DM_NAME_PARAM(&q.qname), DNSTypeName(q.qtype));
+ PenalizeDNSServer(m, qptr, response->h.flags);
+#endif
+ returnEarly = mDNStrue;
}
}
if (returnEarly)
{
- LogInfo("Ignoring %2d Answer%s %2d Authorit%s %2d Additional%s",
- response->h.numAnswers, response->h.numAnswers == 1 ? ", " : "s,",
- response->h.numAuthorities, response->h.numAuthorities == 1 ? "y, " : "ies,",
- response->h.numAdditionals, response->h.numAdditionals == 1 ? "" : "s");
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[Q%d] Ignoring %2d Answer" PUB_S " %2d Authorit" PUB_S " %2d Additional" PUB_S,
+ mDNSVal16(response->h.id),
+ response->h.numAnswers, response->h.numAnswers == 1 ? ", " : "s,",
+ response->h.numAuthorities, response->h.numAuthorities == 1 ? "y, " : "ies,",
+ response->h.numAdditionals, response->h.numAdditionals == 1 ? "" : "s");
// not goto exit because we won't have any CacheFlushRecords and we do not want to
// generate negative cache entries (we want to query the next server)
return;
}
- if (unicastQuestion && DNSSECQuestion(unicastQuestion))
- {
- BumpDNSSECStats(m, kStatsActionSet, kStatsTypeMsgSize, (end - response->data));
- }
}
- // Parse the NSEC3 records from the Authority section before we process
- // the Answer section so that we can cache them along with the proper
- // cache records we create.
- if (mDNSOpaque16IsZero(response->h.id))
- mDNSParseNSEC3Records(m, response, end, InterfaceID, &McastNSEC3Records);
-
for (i = 0; i < totalrecords && ptr && ptr < end; i++)
{
// All responses sent via LL multicast are acceptable for caching
// All responses received over our outbound TCP connections are acceptable for caching
// We accept all records in a unicast response to a multicast query once we find one that
// answers an active question.
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ mDNSBool AcceptableResponse = ResponseMCast || (!querier && !dstaddr) || LLQType || recordAcceptedInResponse;
+#else
mDNSBool AcceptableResponse = ResponseMCast || !dstaddr || LLQType || recordAcceptedInResponse;
+#endif
// (Note that just because we are willing to cache something, that doesn't necessarily make it a trustworthy answer
// to any specific question -- any code reading records from the cache needs to make that determination for itself.)
@@ -9185,13 +9155,6 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
continue;
}
- // We have already parsed the NSEC3 records and cached them approrpriately for
- // multicast responses.
- if (mDNSOpaque16IsZero(response->h.id) && m->rec.r.resrec.rrtype == kDNSType_NSEC3)
- {
- mDNSCoreResetRecord(m);
- continue;
- }
// Don't want to cache OPT or TSIG pseudo-RRs
if (m->rec.r.resrec.rrtype == kDNSType_TSIG)
{
@@ -9224,8 +9187,10 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
// When we receive uDNS LLQ responses, we assume a long cache lifetime --
// In the case of active LLQs, we'll get remove events when the records actually do go away
// In the case of polling LLQs, we assume the record remains valid until the next poll
- if (!mDNSOpaque16IsZero(response->h.id))
+ if (!ResponseIsMDNS)
+ {
m->rec.r.resrec.rroriginalttl = GetEffectiveTTL(LLQType, m->rec.r.resrec.rroriginalttl);
+ }
// If response was not sent via LL multicast,
// then see if it answers a recent query of ours, which would also make it acceptable for caching.
@@ -9239,15 +9204,14 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
// ExpectingUnicastResponseForRecord as the port numbers don't match. uDNS_recvLLQRespose
// has already matched the question using the 64 bit Id in the packet and we use that here.
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ if (querier)
+ {
+ mdns_replace(&m->rec.r.resrec.dnsservice, uDNSService);
+ }
+#else
if (llqMatch != mDNSNULL) m->rec.r.resrec.rDNSServer = uDNSServer = llqMatch->qDNSServer;
-
- // If this is a DNSSEC question that is also LongLived, don't accept records from the
- // Additional/Authority section blindly. We need to go through IsAcceptableResponse below
- // so that NSEC/NSEC3 record are cached in the nseclist if we accept them. This can happen
- // for both negative responses and wildcard expanded positive responses as both of come
- // back with NSEC/NSEC3s.
- if (unicastQuestion && DNSSECQuestion(unicastQuestion))
- AcceptableResponse = mDNSfalse;
+#endif
}
else if (!AcceptableResponse || !dstaddr)
{
@@ -9255,42 +9219,67 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
// that are not long lived e.g., AAAA lookup in a Private domain), it is indicated by !dstaddr.
// Even though it is AcceptableResponse, we still need a DNSServer pointer for the resource records that
// we create.
-
- DNSQuestion *q = ExpectingUnicastResponseForRecord(m, srcaddr, ResponseSrcLocal, dstport, response->h.id, &m->rec.r, !dstaddr);
-
- // Initialize the DNS server on the resource record which will now filter what questions we answer with
- // this record.
- //
- // We could potentially lookup the DNS server based on the source address, but that may not work always
- // and that's why ExpectingUnicastResponseForRecord does not try to verify whether the response came
- // from the DNS server that queried. We follow the same logic here. If we can find a matching quetion based
- // on the "id" and "source port", then this response answers the question and assume the response
- // came from the same DNS server that we sent the query to.
-
- if (q != mDNSNULL)
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ if (querier)
{
- AcceptableResponse = mDNStrue;
- if (!InterfaceID)
- {
- debugf("mDNSCoreReceiveResponse: InterfaceID %p %##s (%s)", q->InterfaceID, q->qname.c, DNSTypeName(q->qtype));
- m->rec.r.resrec.rDNSServer = uDNSServer = q->qDNSServer;
- if (!unicastQuestion) unicastQuestion = q; // Acceptable responses to unicast questions need to have (unicastQuestion != nil)
- }
- else
+ ResourceRecord *const rr = &m->rec.r.resrec;
+ if (Querier_ResourceRecordIsAnswer(rr, querier))
{
- // Accept all remaining records in this unicast response to an mDNS query.
- recordAcceptedInResponse = mDNStrue;
- LogInfo("mDNSCoreReceiveResponse: Accepting response for query: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ const mdns_resolver_type_t resolver_type = mdns_querier_get_resolver_type(querier);
+ if ((resolver_type == mdns_resolver_type_normal) &&
+ (mdns_querier_get_over_tcp_reason(querier) != mdns_query_over_tcp_reason_null))
+ {
+ rr->protocol = mdns_resolver_type_tcp;
+ }
+ else
+ {
+ rr->protocol = resolver_type;
+ }
+ mdns_replace(&rr->dnsservice, uDNSService);
+ AcceptableResponse = mDNStrue;
}
}
else
+#endif
{
- // If we can't find a matching question, we need to see whether we have seen records earlier that matched
- // the question. The code below does that. So, make this record unacceptable for now
- if (!InterfaceID)
+ const DNSQuestion *q;
+ // Initialize the DNS server on the resource record which will now filter what questions we answer with
+ // this record.
+ //
+ // We could potentially lookup the DNS server based on the source address, but that may not work always
+ // and that's why ExpectingUnicastResponseForRecord does not try to verify whether the response came
+ // from the DNS server that queried. We follow the same logic here. If we can find a matching question based
+ // on the "id" and "source port", then this response answers the question and assume the response
+ // came from the same DNS server that we sent the query to.
+ q = ExpectingUnicastResponseForRecord(m, srcaddr, ResponseSrcLocal, dstport, response->h.id, &m->rec.r, !dstaddr);
+ if (q != mDNSNULL)
+ {
+ AcceptableResponse = mDNStrue;
+ if (!InterfaceID)
+ {
+ debugf("mDNSCoreReceiveResponse: InterfaceID %p %##s (%s)", q->InterfaceID, q->qname.c, DNSTypeName(q->qtype));
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ m->rec.r.resrec.rDNSServer = uDNSServer = q->qDNSServer;
+#endif
+ }
+ else
+ {
+ // Accept all remaining records in this unicast response to an mDNS query.
+ recordAcceptedInResponse = mDNStrue;
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d->Q%d] mDNSCoreReceiveResponse: Accepting response for query: " PRI_DM_NAME " (" PUB_S ")",
+ q->request_id, mDNSVal16(q->TargetQID), DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype));
+ }
+ }
+ else
{
- debugf("mDNSCoreReceiveResponse: Can't find question for record name %##s", m->rec.r.resrec.name->c);
- AcceptableResponse = mDNSfalse;
+ // If we can't find a matching question, we need to see whether we have seen records earlier that matched
+ // the question. The code below does that. So, make this record unacceptable for now
+ if (!InterfaceID)
+ {
+ debugf("mDNSCoreReceiveResponse: Can't find question for record name %##s", m->rec.r.resrec.name->c);
+ AcceptableResponse = mDNSfalse;
+ }
}
}
}
@@ -9333,7 +9322,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
}
// 1. Check that this packet resource record does not conflict with any of ours
- if (mDNSOpaque16IsZero(response->h.id) && m->rec.r.resrec.rrtype != kDNSType_NSEC)
+ if (ResponseIsMDNS && m->rec.r.resrec.rrtype != kDNSType_NSEC)
{
if (m->CurrentRecord)
LogMsg("mDNSCoreReceiveResponse ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
@@ -9367,7 +9356,8 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
// else, the packet RR has different type or different rdata -- check to see if this is a conflict
else if (m->rec.r.resrec.rroriginalttl > 0 && PacketRRConflict(m, rr, &m->rec.r))
{
- LogInfo("mDNSCoreReceiveResponse: Pkt Record: %08lX %s", m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r));
+ LogInfo("mDNSCoreReceiveResponse: Pkt Record: %08lX %s (interface %d)",
+ m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r), IIDPrintable(InterfaceID));
LogInfo("mDNSCoreReceiveResponse: Our Record: %08lX %s", rr->resrec.rdatahash, ARDisplayString(m, rr));
// If this record is marked DependentOn another record for conflict detection purposes,
@@ -9409,30 +9399,34 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
// Before we call deregister, check if this is a packet we registered with the sleep proxy.
if (!mDNSCoreRegisteredProxyRecord(m, rr))
{
- // This may be a conflict due to stale packets on the network. Delay probing by a second.
- // If there are conflicts after 3 such attempts, then it is a true conflict.
- if (m->DelayConflictProcessing)
+ if ((rr->ProbingConflictCount == 0) || (m->MPktNum != rr->LastConflictPktNum))
{
- m->DelayConflictProcessing--;
- LogMsg("Possible spurious conflict for %s. Attempt %d at suppressing probes for one second",
- ARDisplayString(m, rr), (MAX_CONFLICT_PROCESSING_DELAYS - m->DelayConflictProcessing));
- rr->ProbeCount = DefaultProbeCountForTypeUnique + 1;
- rr->AnnounceCount = InitialAnnounceCount;
- m->SuppressProbes = NonZeroTime(m->timenow + mDNSPlatformOneSecond);
- InitializeLastAPTime(m, rr);
- RecordProbeFailure(m, rr); // Repeated late conflicts also cause us to back off to the slower probing rate
- }
- else
- {
- LogMsg("mDNSCoreReceiveResponse: ProbeCount %d; will deregister %s", rr->ProbeCount, ARDisplayString(m, rr));
- m->mDNSStats.NameConflicts++;
-#if APPLE_OSX_mDNSResponder
- // See if this record was also registered with any D2D plugins.
- D2D_stop_advertising_record(rr);
+ const NetworkInterfaceInfo *const intf = FirstInterfaceForID(m, InterfaceID);
+ rr->ProbingConflictCount++;
+ rr->LastConflictPktNum = m->MPktNum;
+ if (ResponseMCast && (!intf || intf->SupportsUnicastMDNSResponse) &&
+ (rr->ProbingConflictCount <= kMaxAllowedMCastProbingConflicts))
+ {
+ LogMsg("mDNSCoreReceiveResponse: ProbeCount %d; restarting probing after %d-tick pause due to possibly "
+ "spurious multicast conflict (%d/%d) via interface %d for %s",
+ rr->ProbeCount, kProbingConflictPauseDuration, rr->ProbingConflictCount,
+ kMaxAllowedMCastProbingConflicts, IIDPrintable(InterfaceID), ARDisplayString(m, rr));
+ rr->ProbeCount = DefaultProbeCountForTypeUnique;
+ rr->LastAPTime = m->timenow + kProbingConflictPauseDuration - rr->ThisAPInterval;
+ SetNextAnnounceProbeTime(m, rr);
+ }
+ else
+ {
+ LogMsg("mDNSCoreReceiveResponse: ProbeCount %d; will deregister %s due to %scast conflict via interface %d",
+ rr->ProbeCount, ARDisplayString(m, rr), ResponseMCast ? "multi" : "uni", IIDPrintable(InterfaceID));
+ m->mDNSStats.NameConflicts++;
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+ // See if this record was also registered with any D2D plugins.
+ D2D_stop_advertising_record(rr);
#endif
- mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
+ mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
+ }
}
-
}
}
// We assumed this record must be unique, but we were wrong. (e.g. There are two mDNSResponders on the
@@ -9444,7 +9438,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
{
LogMsg("mDNSCoreReceiveResponse: Unexpected conflict discarding %s", ARDisplayString(m, rr));
m->mDNSStats.KnownUniqueNameConflicts++;
-#if APPLE_OSX_mDNSResponder
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
D2D_stop_advertising_record(rr);
#endif
mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
@@ -9457,42 +9451,57 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
// If the packet record has the cache-flush bit set, then we check to see if we
// have any record(s) of the same type that we should re-assert to rescue them
// (see note about "multi-homing and bridged networks" at the end of this function).
- else if (m->rec.r.resrec.rrtype == rr->resrec.rrtype)
- if ((m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) && (mDNSu32)(m->timenow - rr->LastMCTime) > (mDNSu32)mDNSPlatformOneSecond/2)
- { rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; }
+ else if ((m->rec.r.resrec.rrtype == rr->resrec.rrtype) &&
+ (m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) &&
+ ((mDNSu32)(m->timenow - rr->LastMCTime) > (mDNSu32)mDNSPlatformOneSecond/2) &&
+ ResourceRecordIsValidAnswer(rr))
+ {
+ rr->ImmedAnswer = mDNSInterfaceMark;
+ m->NextScheduledResponse = m->timenow;
+ }
}
}
}
- nseclist = mDNSfalse;
if (!AcceptableResponse)
{
- AcceptableResponse = IsResponseAcceptable(m, CacheFlushRecords, unicastQuestion, &nseclist);
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+ #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ not_answer_but_required_for_dnssec = adds_denial_records_in_cache_record(&m->rec.r.resrec,
+ querier != mDNSNULL && mdns_querier_get_dnssec_ok(querier), &denial_of_existence_records);
+ #else
+ not_answer_but_required_for_dnssec = mDNSfalse;
+ #endif
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+ AcceptableResponse = IsResponseAcceptable(m, CacheFlushRecords);
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ if (AcceptableResponse) mdns_replace(&m->rec.r.resrec.dnsservice, uDNSService);
+#else
if (AcceptableResponse) m->rec.r.resrec.rDNSServer = uDNSServer;
+#endif
}
// 2. See if we want to add this packet resource record to our cache
// We only try to cache answers if we have a cache to put them in
// Also, we ignore any apparent attempts at cache poisoning unicast to us that do not answer any outstanding active query
- if (!AcceptableResponse) LogInfo("mDNSCoreReceiveResponse ignoring %s", CRDisplayString(m, &m->rec.r));
+ if (!AcceptableResponse) {
+ const char* savedString = "";
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+ savedString = (not_answer_but_required_for_dnssec ? "Saved for DNSSEC" : "");
+#endif
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[Q%d] mDNSCoreReceiveResponse ignoring " PRI_S " %s",
+ mDNSVal16(response->h.id), CRDisplayString(m, &m->rec.r), savedString);
+ }
+
if (m->rrcache_size && AcceptableResponse)
{
const mDNSu32 slot = HashSlotFromNameHash(m->rec.r.resrec.namehash);
CacheGroup *cg = CacheGroupForRecord(m, &m->rec.r.resrec);
CacheRecord *rr = mDNSNULL;
- if (McastNSEC3Records)
- InitializeAnonInfoForCR(m, &McastNSEC3Records, &m->rec.r);
-
// 2a. Check if this packet resource record is already in our cache.
- //
- // If this record should go in the nseclist, don't look in the cache for updating it.
- // They are supposed to be cached under the "nsec" field of the cache record for
- // validation. Just create the cache record.
- if (!nseclist)
- {
- rr = mDNSCoreReceiveCacheCheck(m, response, LLQType, slot, cg, unicastQuestion, &cfp, &NSECCachePtr, InterfaceID);
- }
+ rr = mDNSCoreReceiveCacheCheck(m, response, LLQType, slot, cg, &cfp, InterfaceID);
// If packet resource record not in our cache, add it now
// (unless it is just a deletion of a record we never had, in which case we don't care)
@@ -9510,36 +9519,16 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
// Below, where we walk the CacheFlushRecords list, we either call CacheRecordDeferredAdd()
// to immediately to generate answer callbacks, or we call ScheduleNextCacheCheckTime()
// to schedule an mDNS_Execute task at the appropriate time.
- rr = CreateNewCacheEntry(m, slot, cg, delay, !nseclist, srcaddr);
+ rr = CreateNewCacheEntry(m, slot, cg, delay, mDNStrue, srcaddr);
if (rr)
{
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+ set_denial_records_in_cache_record(rr, &denial_of_existence_records);
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+
rr->responseFlags = response->h.flags;
- // If we are not creating signatures, then we need to inform DNSSEC so that
- // it does not wait forever. Don't do this if we got NSEC records
- // as it indicates that this name does not exist.
- if (rr->resrec.rrtype == kDNSType_RRSIG && !nseclist)
- {
- rrsigsCreated = mDNStrue;
- }
- // Remember whether we created a cache record in response to a DNSSEC question.
- // This helps DNSSEC code not to reissue the question to fetch the DNSSEC records.
- rr->CRDNSSECQuestion = 0;
- if (unicastQuestion && DNSSECQuestion(unicastQuestion))
- {
- LogInfo("mDNSCoreReceiveResponse: CRDNSSECQuestion set for new record %s, question %##s (%s)", CRDisplayString(m, rr),
- unicastQuestion->qname.c, DNSTypeName(unicastQuestion->qtype));
- rr->CRDNSSECQuestion = 1;
- }
- // NSEC/NSEC3 records and its signatures are cached with the negative cache entry
- // which we should be creating below. It is also needed in the wildcard
- // expanded answer case and in that case it is cached along with the answer.
- if (nseclist)
- {
- rr->TimeRcvd = m->timenow;
- *nsecp = rr;
- nsecp = &rr->next;
- }
- else if (AddToCFList)
+
+ if (AddToCFList)
{
*cfp = rr;
cfp = &rr->NextInCFList;
@@ -9551,13 +9540,6 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
}
}
}
- else
- {
- if (rr && rr->resrec.AnonInfo && m->rec.r.resrec.AnonInfo)
- {
- CopyAnonInfoForCR(m, rr, &m->rec.r);
- }
- }
}
mDNSCoreResetRecord(m);
}
@@ -9591,127 +9573,133 @@ exit:
// *decrease* a record's remaining lifetime, never *increase* it.
for (r2 = cg ? cg->members : mDNSNULL; r2; r2=r2->next)
{
- mDNSu16 id1;
- mDNSu16 id2;
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ mDNSBool match;
+#else
+ mDNSu32 id1;
+ mDNSu32 id2;
+#endif
if (!r1->resrec.InterfaceID)
{
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ match = (r1->resrec.dnsservice == r2->resrec.dnsservice) ? mDNStrue : mDNSfalse;
+#else
id1 = (r1->resrec.rDNSServer ? r1->resrec.rDNSServer->resGroupID : 0);
id2 = (r2->resrec.rDNSServer ? r2->resrec.rDNSServer->resGroupID : 0);
+#endif
}
else
{
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ match = mDNStrue;
+#else
id1 = id2 = 0;
+#endif
}
- // When we receive new RRSIGs e.g., for DNSKEY record, we should not flush the old
- // RRSIGS e.g., for TXT record. To do so, we need to look at the typeCovered field of
- // the new RRSIG that we received. Process only if the typeCovered matches.
- if ((r1->resrec.rrtype == r2->resrec.rrtype) && (r1->resrec.rrtype == kDNSType_RRSIG))
- {
- rdataRRSig *rrsig1 = (rdataRRSig *)(((RDataBody2 *)(r1->resrec.rdata->u.data))->data);
- rdataRRSig *rrsig2 = (rdataRRSig *)(((RDataBody2 *)(r2->resrec.rdata->u.data))->data);
- if (swap16(rrsig1->typeCovered) != swap16(rrsig2->typeCovered))
- {
- debugf("mDNSCoreReceiveResponse: Received RRSIG typeCovered %s, found %s, not processing",
- DNSTypeName(swap16(rrsig1->typeCovered)), DNSTypeName(swap16(rrsig2->typeCovered)));
- continue;
- }
- }
-
// For Unicast (null InterfaceID) the resolver IDs should also match
if ((r1->resrec.InterfaceID == r2->resrec.InterfaceID) &&
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ (r1->resrec.InterfaceID || match) &&
+#else
(r1->resrec.InterfaceID || (id1 == id2)) &&
+#endif
r1->resrec.rrtype == r2->resrec.rrtype &&
- r1->resrec.rrclass == r2->resrec.rrclass)
+ r1->resrec.rrclass == r2->resrec.rrclass
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+ // 2 RRSIGs need to cover the same DNS type to be identified as one RRSET, and have the same TTL
+ && are_records_in_the_same_cache_set_for_dnssec(&r1->resrec, &r2->resrec)
+#endif
+ )
{
- if (r1->resrec.mortality == Mortality_Mortal && r2->resrec.mortality != Mortality_Mortal)
- {
- verbosedebugf("mDNSCoreReceiveResponse: R1(%p) is being immortalized by R2(%p)", r1, r2);
- r1->resrec.mortality = Mortality_Immortal; // Immortalize the replacement record
- }
-
- // If record is recent, just ensure the whole RRSet has the same TTL (as required by DNS semantics)
- // else, if record is old, mark it to be flushed
- if (m->timenow - r2->TimeRcvd < mDNSPlatformOneSecond && RRExpireTime(r2) - m->timenow > mDNSPlatformOneSecond)
- {
- // If we find mismatched TTLs in an RRSet, correct them.
- // We only do this for records with a TTL of 2 or higher. It's possible to have a
- // goodbye announcement with the cache flush bit set (or a case-change on record rdata,
- // which we treat as a goodbye followed by an addition) and in that case it would be
- // inappropriate to synchronize all the other records to a TTL of 0 (or 1).
-
- // We suppress the message for the specific case of correcting from 240 to 60 for type TXT,
- // because certain early Bonjour devices are known to have this specific mismatch, and
- // there's no point filling syslog with messages about something we already know about.
- // We also don't log this for uDNS responses, since a caching name server is obliged
- // to give us an aged TTL to correct for how long it has held the record,
- // so our received TTLs are expected to vary in that case
-
- // We also suppress log message in the case of SRV records that are received
- // with a TTL of 4500 that are already cached with a TTL of 120 seconds, since
- // this behavior was observed for a number of discoveryd based AppleTV's in iOS 8
- // GM builds.
- if (r2->resrec.rroriginalttl != r1->resrec.rroriginalttl && r1->resrec.rroriginalttl > 1)
+ if (r1->resrec.mortality == Mortality_Mortal && r2->resrec.mortality != Mortality_Mortal)
{
- if (!(r2->resrec.rroriginalttl == 240 && r1->resrec.rroriginalttl == 60 && r2->resrec.rrtype == kDNSType_TXT) &&
- !(r2->resrec.rroriginalttl == 120 && r1->resrec.rroriginalttl == 4500 && r2->resrec.rrtype == kDNSType_SRV) &&
- mDNSOpaque16IsZero(response->h.id))
- LogInfo("Correcting TTL from %4d to %4d for %s",
- r2->resrec.rroriginalttl, r1->resrec.rroriginalttl, CRDisplayString(m, r2));
- r2->resrec.rroriginalttl = r1->resrec.rroriginalttl;
+ verbosedebugf("mDNSCoreReceiveResponse: R1(%p) is being immortalized by R2(%p)", r1, r2);
+ r1->resrec.mortality = Mortality_Immortal; // Immortalize the replacement record
}
- r2->TimeRcvd = m->timenow;
- SetNextCacheCheckTimeForRecord(m, r2);
- }
- else if (r2->resrec.InterfaceID) // else, if record is old, mark it to be flushed
- {
- verbosedebugf("Cache flush new %p age %d expire in %d %s", r1, m->timenow - r1->TimeRcvd, RRExpireTime(r1) - m->timenow, CRDisplayString(m, r1));
- verbosedebugf("Cache flush old %p age %d expire in %d %s", r2, m->timenow - r2->TimeRcvd, RRExpireTime(r2) - m->timenow, CRDisplayString(m, r2));
- // We set stale records to expire in one second.
- // This gives the owner a chance to rescue it if necessary.
- // This is important in the case of multi-homing and bridged networks:
- // Suppose host X is on Ethernet. X then connects to an AirPort base station, which happens to be
- // bridged onto the same Ethernet. When X announces its AirPort IP address with the cache-flush bit
- // set, the AirPort packet will be bridged onto the Ethernet, and all other hosts on the Ethernet
- // will promptly delete their cached copies of the (still valid) Ethernet IP address record.
- // By delaying the deletion by one second, we give X a change to notice that this bridging has
- // happened, and re-announce its Ethernet IP address to rescue it from deletion from all our caches.
-
- // We set UnansweredQueries to MaxUnansweredQueries to avoid expensive and unnecessary
- // final expiration queries for this record.
-
- // If a record is deleted twice, first with an explicit DE record, then a second time by virtue of the cache
- // flush bit on the new record replacing it, then we allow the record to be deleted immediately, without the usual
- // one-second grace period. This improves responsiveness for mDNS_Update(), as used for things like iChat status updates.
- // <rdar://problem/5636422> Updating TXT records is too slow
- // We check for "rroriginalttl == 1" because we want to include records tagged by the "packet TTL is zero" check above,
- // which sets rroriginalttl to 1, but not records tagged by the rdata case-change check, which sets rroriginalttl to 0.
- if (r2->TimeRcvd == m->timenow && r2->resrec.rroriginalttl == 1 && r2->UnansweredQueries == MaxUnansweredQueries)
+
+ // If record is recent, just ensure the whole RRSet has the same TTL (as required by DNS semantics)
+ // else, if record is old, mark it to be flushed
+ if (m->timenow - r2->TimeRcvd < mDNSPlatformOneSecond && RRExpireTime(r2) - m->timenow > mDNSPlatformOneSecond)
{
- LogInfo("Cache flush for DE record %s", CRDisplayString(m, r2));
- r2->resrec.rroriginalttl = 0;
+ // If we find mismatched TTLs in an RRSet, correct them.
+ // We only do this for records with a TTL of 2 or higher. It's possible to have a
+ // goodbye announcement with the cache flush bit set (or a case-change on record rdata,
+ // which we treat as a goodbye followed by an addition) and in that case it would be
+ // inappropriate to synchronize all the other records to a TTL of 0 (or 1).
+
+ // We suppress the message for the specific case of correcting from 240 to 60 for type TXT,
+ // because certain early Bonjour devices are known to have this specific mismatch, and
+ // there's no point filling syslog with messages about something we already know about.
+ // We also don't log this for uDNS responses, since a caching name server is obliged
+ // to give us an aged TTL to correct for how long it has held the record,
+ // so our received TTLs are expected to vary in that case
+
+ // We also suppress log message in the case of SRV records that are received
+ // with a TTL of 4500 that are already cached with a TTL of 120 seconds, since
+ // this behavior was observed for a number of discoveryd based AppleTV's in iOS 8
+ // GM builds.
+ if (r2->resrec.rroriginalttl != r1->resrec.rroriginalttl && r1->resrec.rroriginalttl > 1)
+ {
+ if (!(r2->resrec.rroriginalttl == 240 && r1->resrec.rroriginalttl == 60 && r2->resrec.rrtype == kDNSType_TXT) &&
+ !(r2->resrec.rroriginalttl == 120 && r1->resrec.rroriginalttl == 4500 && r2->resrec.rrtype == kDNSType_SRV) &&
+ ResponseIsMDNS)
+ LogInfo("Correcting TTL from %4d to %4d for %s",
+ r2->resrec.rroriginalttl, r1->resrec.rroriginalttl, CRDisplayString(m, r2));
+ r2->resrec.rroriginalttl = r1->resrec.rroriginalttl;
+ }
+ r2->TimeRcvd = m->timenow;
+ SetNextCacheCheckTimeForRecord(m, r2);
}
- else if (RRExpireTime(r2) - m->timenow > mDNSPlatformOneSecond)
+ else if (r2->resrec.InterfaceID) // else, if record is old, mark it to be flushed
{
- // We only set a record to expire in one second if it currently has *more* than a second to live
- // If it's already due to expire in a second or less, we just leave it alone
- r2->resrec.rroriginalttl = 1;
- r2->UnansweredQueries = MaxUnansweredQueries;
- r2->TimeRcvd = m->timenow - 1;
- // We use (m->timenow - 1) instead of m->timenow, because we use that to identify records
- // that we marked for deletion via an explicit DE record
+ verbosedebugf("Cache flush new %p age %d expire in %d %s", r1, m->timenow - r1->TimeRcvd, RRExpireTime(r1) - m->timenow, CRDisplayString(m, r1));
+ verbosedebugf("Cache flush old %p age %d expire in %d %s", r2, m->timenow - r2->TimeRcvd, RRExpireTime(r2) - m->timenow, CRDisplayString(m, r2));
+ // We set stale records to expire in one second.
+ // This gives the owner a chance to rescue it if necessary.
+ // This is important in the case of multi-homing and bridged networks:
+ // Suppose host X is on Ethernet. X then connects to an AirPort base station, which happens to be
+ // bridged onto the same Ethernet. When X announces its AirPort IP address with the cache-flush bit
+ // set, the AirPort packet will be bridged onto the Ethernet, and all other hosts on the Ethernet
+ // will promptly delete their cached copies of the (still valid) Ethernet IP address record.
+ // By delaying the deletion by one second, we give X a change to notice that this bridging has
+ // happened, and re-announce its Ethernet IP address to rescue it from deletion from all our caches.
+
+ // We set UnansweredQueries to MaxUnansweredQueries to avoid expensive and unnecessary
+ // final expiration queries for this record.
+
+ // If a record is deleted twice, first with an explicit DE record, then a second time by virtue of the cache
+ // flush bit on the new record replacing it, then we allow the record to be deleted immediately, without the usual
+ // one-second grace period. This improves responsiveness for mDNS_Update(), as used for things like iChat status updates.
+ // <rdar://problem/5636422> Updating TXT records is too slow
+ // We check for "rroriginalttl == 1" because we want to include records tagged by the "packet TTL is zero" check above,
+ // which sets rroriginalttl to 1, but not records tagged by the rdata case-change check, which sets rroriginalttl to 0.
+ if (r2->TimeRcvd == m->timenow && r2->resrec.rroriginalttl == 1 && r2->UnansweredQueries == MaxUnansweredQueries)
+ {
+ LogInfo("Cache flush for DE record %s", CRDisplayString(m, r2));
+ r2->resrec.rroriginalttl = 0;
+ }
+ else if (RRExpireTime(r2) - m->timenow > mDNSPlatformOneSecond)
+ {
+ // We only set a record to expire in one second if it currently has *more* than a second to live
+ // If it's already due to expire in a second or less, we just leave it alone
+ r2->resrec.rroriginalttl = 1;
+ r2->UnansweredQueries = MaxUnansweredQueries;
+ r2->TimeRcvd = m->timenow - 1;
+ // We use (m->timenow - 1) instead of m->timenow, because we use that to identify records
+ // that we marked for deletion via an explicit DE record
+ }
+ SetNextCacheCheckTimeForRecord(m, r2);
}
- SetNextCacheCheckTimeForRecord(m, r2);
- }
- else
- {
-#if AWD_METRICS
+ else
+ {
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
if (r2->resrec.mortality == Mortality_Ghost)
{
DNSQuestion * q;
for (q = m->Questions; q; q=q->next)
{
if (!q->LongLived && ActiveQuestion(q) &&
- ResourceRecordAnswersQuestion(&r2->resrec, q) &&
+ CacheRecordAnswersQuestion(r2, q) &&
q->metrics.expiredAnswerState == ExpiredAnswer_AnsweredWithExpired)
{
q->metrics.expiredAnswerState = ExpiredAnswer_ExpiredAnswerChanged;
@@ -9720,37 +9708,14 @@ exit:
}
#endif
// Old uDNS records are scheduled to be purged instead of given at most one second to live.
- r2->resrec.mortality = Mortality_Mortal; // We want it purged, so remove any immortality
mDNS_PurgeCacheResourceRecord(m, r2);
purgedRecords = mDNStrue;
}
}
- }
+ }
if (r1->DelayDelivery) // If we were planning to delay delivery of this record, see if we still need to
{
- // If we had a unicast question for this response with at least one positive answer and we
- // have NSECRecords, it is most likely a wildcard expanded answer. Cache the NSEC and its
- // signatures along with the cache record which will be used for validation later. If
- // we rescued a few records earlier in this function, then NSECCachePtr would be set. In that
- // use that instead.
- if (response->h.numAnswers && unicastQuestion && NSECRecords)
- {
- if (!NSECCachePtr)
- {
- LogInfo("mDNSCoreReceiveResponse: Updating NSECCachePtr to %s", CRDisplayString(m, r1));
- NSECCachePtr = r1;
- }
- // Note: We need to do this before we call CacheRecordDeferredAdd as this
- // might start the verification process which needs these NSEC records
- if (!AddNSECSForCacheRecord(m, NSECRecords, NSECCachePtr, rcode))
- {
- LogInfo("mDNSCoreReceiveResponse: AddNSECSForCacheRecord failed to add NSEC for %s", CRDisplayString(m, NSECCachePtr));
- FreeNSECRecords(m, NSECRecords);
- }
- NSECRecords = mDNSNULL;
- NSECCachePtr = mDNSNULL;
- }
if (r1->resrec.InterfaceID)
{
r1->DelayDelivery = CheckForSoonToExpireRecords(m, r1->resrec.name, r1->resrec.namehash);
@@ -9767,41 +9732,19 @@ exit:
}
}
- // If we have not consumed the NSEC records yet e.g., just refreshing the cache,
- // update them now for future validations.
- if (NSECRecords && NSECCachePtr)
- {
- LogInfo("mDNSCoreReceieveResponse: Updating NSEC records in %s", CRDisplayString(m, NSECCachePtr));
- if (!AddNSECSForCacheRecord(m, NSECRecords, NSECCachePtr, rcode))
- {
- LogInfo("mDNSCoreReceiveResponse: AddNSECSForCacheRecord failed to add NSEC for %s", CRDisplayString(m, NSECCachePtr));
- FreeNSECRecords(m, NSECRecords);
- }
- NSECRecords = mDNSNULL;
- NSECCachePtr = mDNSNULL;
- }
-
- // If there is at least one answer and we did not create RRSIGs and there was a
- // ValidatingResponse question waiting for this response, give a hint that no RRSIGs
- // were created. We don't need to give a hint:
- //
- // - if we have no answers, the mDNSCoreReceiveNoUnicastAnswers below should
- // generate a negative response
- //
- // - if we have NSECRecords, it means we might have a potential proof for
- // non-existence of name that we are looking for
- //
- if (response->h.numAnswers && !rrsigsCreated && DNSSECQuestion && !NSECRecords)
- mDNSCoreReceiveNoDNSSECAnswers(m, response, end, dstaddr, dstport, InterfaceID);
-
// See if we need to generate negative cache entries for unanswered unicast questions
- mDNSCoreReceiveNoUnicastAnswers(m, response, end, dstaddr, dstport, InterfaceID, LLQType, rcode, NSECRecords);
+ mDNSCoreReceiveNoUnicastAnswers(m, response, end, dstaddr, dstport, InterfaceID,
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ querier, uDNSService,
+#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+ &denial_of_existence_records,
+#endif
+ LLQType);
- if (McastNSEC3Records)
- {
- debugf("mDNSCoreReceiveResponse: McastNSEC3Records not used");
- FreeNSECRecords(m, McastNSEC3Records);
- }
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+ destroy_denial_of_existence_records_t_if_nonnull(denial_of_existence_records);
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
}
// ScheduleWakeup causes all proxy records with WakeUp.HMAC matching mDNSEthAddr 'e' to be deregistered, causing
@@ -10339,7 +10282,7 @@ mDNSlocal void mDNSCoreReceiveUpdate(mDNS *const m,
if (!InterfaceID || !m->SPSSocket || !mDNSSameIPPort(dstport, m->SPSSocket->port)) return;
if (mDNS_PacketLoggingEnabled)
- DumpPacket(mStatus_NoError, mDNSfalse, "UDP", srcaddr, srcport, dstaddr, dstport, msg, end);
+ DumpPacket(mStatus_NoError, mDNSfalse, "UDP", srcaddr, srcport, dstaddr, dstport, msg, end, InterfaceID);
ptr = LocateOptRR(msg, end, DNSOpt_LeaseData_Space + DNSOpt_OwnerData_ID_Space);
if (ptr)
@@ -10404,7 +10347,7 @@ mDNSlocal void mDNSCoreReceiveUpdate(mDNS *const m,
if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative)
{
mDNSu16 RDLengthMem = GetRDLengthMem(&m->rec.r.resrec);
- AuthRecord *ar = mDNSPlatformMemAllocate(sizeof(AuthRecord) - sizeof(RDataBody) + RDLengthMem);
+ AuthRecord *ar = (AuthRecord *) mDNSPlatformMemAllocateClear(sizeof(AuthRecord) - sizeof(RDataBody) + RDLengthMem);
if (!ar)
{
m->omsg.h.flags.b[1] |= kDNSFlag1_RC_Refused;
@@ -10468,7 +10411,7 @@ mDNSlocal void mDNSCoreReceiveUpdate(mDNS *const m,
}
}
- if (p) mDNSSendDNSMessage(m, &m->omsg, p, InterfaceID, m->SPSSocket, srcaddr, srcport, mDNSNULL, mDNSNULL, mDNSfalse);
+ if (p) mDNSSendDNSMessage(m, &m->omsg, p, InterfaceID, mDNSNULL, m->SPSSocket, srcaddr, srcport, mDNSNULL, mDNSfalse);
mDNS_SendKeepalives(m);
}
@@ -10494,7 +10437,7 @@ mDNSlocal mDNSu32 mDNSGenerateOwnerOptForInterface(mDNS *const m, const mDNSInte
{
// Put all the integer values in IETF byte-order (MSB first, LSB second)
SwapDNSHeaderBytes(msg);
- length = (end - msg->data);
+ length = (mDNSu32)(end - msg->data);
}
else
LogSPS("mDNSGenerateOwnerOptForInterface: Failed to generate owner OPT record");
@@ -10573,8 +10516,13 @@ mDNSlocal void mDNSCoreReceiveUpdateR(mDNS *const m, const DNSMessage *const msg
if (m->SleepLimit) m->NextScheduledSPRetry = m->timenow;
}
-mDNSexport void MakeNegativeCacheRecord(mDNS *const m, CacheRecord *const cr,
- const domainname *const name, const mDNSu32 namehash, const mDNSu16 rrtype, const mDNSu16 rrclass, mDNSu32 ttl_seconds, mDNSInterfaceID InterfaceID, DNSServer *dnsserver)
+mDNSexport void MakeNegativeCacheRecord(mDNS *const m, CacheRecord *const cr, const domainname *const name,
+ const mDNSu32 namehash, const mDNSu16 rrtype, const mDNSu16 rrclass, mDNSu32 ttl_seconds, mDNSInterfaceID InterfaceID,
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ mdns_dns_service_t service)
+#else
+ DNSServer *dnsserver)
+#endif
{
if (cr == &m->rec.r && m->rec.r.resrec.RecordType)
LogFatalError("MakeNegativeCacheRecord: m->rec appears to be already in use for %s", CRDisplayString(m, &m->rec.r));
@@ -10582,7 +10530,11 @@ mDNSexport void MakeNegativeCacheRecord(mDNS *const m, CacheRecord *const cr,
// Create empty resource record
cr->resrec.RecordType = kDNSRecordTypePacketNegative;
cr->resrec.InterfaceID = InterfaceID;
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ mdns_replace(&cr->resrec.dnsservice, service);
+#else
cr->resrec.rDNSServer = dnsserver;
+#endif
cr->resrec.name = name; // Will be updated to point to cg->name when we call CreateNewCacheEntry
cr->resrec.rrtype = rrtype;
cr->resrec.rrclass = rrclass;
@@ -10598,18 +10550,30 @@ mDNSexport void MakeNegativeCacheRecord(mDNS *const m, CacheRecord *const cr,
cr->TimeRcvd = m->timenow;
cr->DelayDelivery = 0;
cr->NextRequiredQuery = m->timenow;
+#if MDNSRESPONDER_SUPPORTS(APPLE, CACHE_ANALYTICS)
+ cr->LastCachedAnswerTime= 0;
+#endif
cr->CRActiveQuestion = mDNSNULL;
cr->UnansweredQueries = 0;
cr->LastUnansweredTime = 0;
cr->NextInCFList = mDNSNULL;
- cr->nsec = mDNSNULL;
cr->soa = mDNSNULL;
- cr->CRDNSSECQuestion = 0;
// Initialize to the basic one and the caller can set it to more
// specific based on the response if any
cr->responseFlags = ResponseFlags;
}
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+mDNSexport void mDNSCoreReceiveForQuerier(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
+ mdns_querier_t querier, mdns_dns_service_t dnsservice)
+{
+ SwapDNSHeaderBytes(msg);
+ mDNS_Lock(m);
+ mDNSCoreReceiveResponse(m, msg, end, mDNSNULL, zeroIPPort, mDNSNULL, zeroIPPort, querier, dnsservice, mDNSNULL);
+ mDNS_Unlock(m);
+}
+#endif
+
mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport,
const mDNSInterfaceID InterfaceID)
@@ -10667,7 +10631,7 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNS
// We use zero addresses and all-ones addresses at various places in the code to indicate special values like "no address"
// If we accept and try to process a packet with zero or all-ones source address, that could really mess things up
- if (srcaddr && !mDNSAddressIsValid(srcaddr)) { debugf("mDNSCoreReceive ignoring packet from %#a", srcaddr); return; }
+ if (!mDNSAddressIsValid(srcaddr)) { debugf("mDNSCoreReceive ignoring packet from %#a", srcaddr); return; }
mDNS_Lock(m);
m->PktNum++;
@@ -10692,13 +10656,17 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNS
{
ifid = mDNSInterface_Any;
if (mDNS_PacketLoggingEnabled)
- DumpPacket(mStatus_NoError, mDNSfalse, TLS ? "TLS" : !dstaddr ? "TCP" : "UDP", srcaddr, srcport, dstaddr, dstport, msg, end);
+ DumpPacket(mStatus_NoError, mDNSfalse, TLS ? "TLS" : !dstaddr ? "TCP" : "UDP", srcaddr, srcport, dstaddr, dstport, msg, end, InterfaceID);
uDNS_ReceiveMsg(m, msg, end, srcaddr, srcport);
// Note: mDNSCore also needs to get access to received unicast responses
}
#endif
if (QR_OP == StdQ) mDNSCoreReceiveQuery (m, msg, end, srcaddr, srcport, dstaddr, dstport, ifid);
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ else if (QR_OP == StdR) mDNSCoreReceiveResponse(m, msg, end, srcaddr, srcport, dstaddr, dstport, mDNSNULL, mDNSNULL, ifid);
+#else
else if (QR_OP == StdR) mDNSCoreReceiveResponse(m, msg, end, srcaddr, srcport, dstaddr, dstport, ifid);
+#endif
else if (QR_OP == UpdQ) mDNSCoreReceiveUpdate (m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID);
else if (QR_OP == UpdR) mDNSCoreReceiveUpdateR (m, msg, end, srcaddr, InterfaceID);
else
@@ -10735,17 +10703,6 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNS
#pragma mark - Searcher Functions
#endif
-// Targets are considered the same if both queries are untargeted, or
-// if both are targeted to the same address+port
-// (If Target address is zero, TargetPort is undefined)
-#define SameQTarget(A,B) (((A)->Target.type == mDNSAddrType_None && (B)->Target.type == mDNSAddrType_None) || \
- (mDNSSameAddress(& (A)->Target, & (B)->Target) && mDNSSameIPPort((A)->TargetPort, (B)->TargetPort)))
-
-// SameQuestionKind is true if *both* questions are either multicast or unicast
-// TargetQID is used for this determination.
-#define SameQuestionKind(A,B) ((mDNSOpaque16IsZero(A) && mDNSOpaque16IsZero(B)) || \
- ((!mDNSOpaque16IsZero(A)) && (!mDNSOpaque16IsZero(B))))
-
// Note: We explicitly disallow making a public query be a duplicate of a private one. This is to avoid the
// circular deadlock where a client does a query for something like "dns-sd -Q _dns-query-tls._tcp.company.com SRV"
// and we have a key for company.com, so we try to locate the private query server for company.com, which necessarily entails
@@ -10765,8 +10722,9 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNS
// (a) long-lived and
// (b) being performed by a unicast DNS long-lived query (either full LLQ, or polling)
// for multicast questions, we don't want to treat LongLived as anything special
-#define IsLLQ(Q) ((Q)->LongLived && !mDNSOpaque16IsZero((Q)->TargetQID))
-#define IsAWDLIncluded(Q) (((Q)->flags & kDNSServiceFlagsIncludeAWDL) != 0)
+#define IsLLQ(Q) ((Q)->LongLived && !mDNSOpaque16IsZero((Q)->TargetQID))
+#define AWDLIsIncluded(Q) (((Q)->flags & kDNSServiceFlagsIncludeAWDL) != 0)
+#define SameQuestionKind(Q1, Q2) (mDNSOpaque16IsZero((Q1)->TargetQID) == mDNSOpaque16IsZero((Q2)->TargetQID))
mDNSlocal DNSQuestion *FindDuplicateQuestion(const mDNS *const m, const DNSQuestion *const question)
{
@@ -10775,24 +10733,24 @@ mDNSlocal DNSQuestion *FindDuplicateQuestion(const mDNS *const m, const DNSQuest
// This prevents circular references, where two questions are each marked as a duplicate of the other.
// Accordingly, we break out of the loop when we get to 'question', because there's no point searching
// further in the list.
- for (q = m->Questions; q && q != question; q=q->next) // Scan our list for another question
- if (q->InterfaceID == question->InterfaceID && // with the same InterfaceID,
- SameQTarget(q, question) && // and same unicast/multicast target settings
- q->qtype == question->qtype && // type,
- q->qclass == question->qclass && // class,
- IsLLQ(q) == IsLLQ(question) && // and long-lived status matches
- (!q->AuthInfo || question->AuthInfo) && // to avoid deadlock, don't make public query dup of a private one
- (q->AnonInfo == question->AnonInfo) && // Anonymous query not a dup of normal query
- (q->SuppressQuery == question->SuppressQuery) && // Questions that are suppressed/not suppressed
- (q->ValidationRequired == question->ValidationRequired) && // Questions that require DNSSEC validation
- (q->ValidatingResponse == question->ValidatingResponse) && // Questions that are validating responses using DNSSEC
- (q->DisallowPID == question->DisallowPID) && // Disallowing a PID should not affect a PID that is allowed
- (q->BrowseThreshold == question->BrowseThreshold) && // browse thresholds must match
- q->qnamehash == question->qnamehash &&
- (IsAWDLIncluded(q) == IsAWDLIncluded(question)) && // Inclusion of AWDL interface must match
- SameQuestionKind(q->TargetQID, question->TargetQID) && // mDNS or uDNS must match
- SameDomainName(&q->qname, &question->qname)) // and name
- return(q);
+ for (q = m->Questions; q && (q != question); q = q->next)
+ {
+ if (!SameQuestionKind(q, question)) continue;
+ if (q->qnamehash != question->qnamehash) continue;
+ if (q->InterfaceID != question->InterfaceID) continue;
+ if (q->qtype != question->qtype) continue;
+ if (q->qclass != question->qclass) continue;
+ if (IsLLQ(q) != IsLLQ(question)) continue;
+ if (q->AuthInfo && !question->AuthInfo) continue;
+ if (!q->Suppressed != !question->Suppressed) continue;
+ if (q->BrowseThreshold != question->BrowseThreshold) continue;
+ if (AWDLIsIncluded(q) != AWDLIsIncluded(question)) continue;
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ if (q->dnsservice != question->dnsservice) continue;
+#endif
+ if (!SameDomainName(&q->qname, &question->qname)) continue;
+ return(q);
+ }
return(mDNSNULL);
}
@@ -10806,9 +10764,11 @@ mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, DNSQuestion *const questi
// question as a duplicate.
if (question->DuplicateOf)
{
- LogInfo("UpdateQuestionDuplicates: question %p %##s (%s) duplicate of %p %##s (%s)",
- question, question->qname.c, DNSTypeName(question->qtype),
- question->DuplicateOf, question->DuplicateOf->qname.c, DNSTypeName(question->DuplicateOf->qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+ "[R%d->DupQ%d->Q%d] UpdateQuestionDuplicates: question %p " PRI_DM_NAME " (" PUB_S ") duplicate of %p " PRI_DM_NAME " (" PUB_S ")",
+ question->request_id, mDNSVal16(question->TargetQID), mDNSVal16(question->DuplicateOf->TargetQID),
+ question, DM_NAME_PARAM(&question->qname), DNSTypeName(question->qtype), question->DuplicateOf,
+ DM_NAME_PARAM(&question->DuplicateOf->qname), DNSTypeName(question->DuplicateOf->qtype));
return;
}
@@ -10832,15 +10792,25 @@ mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, DNSQuestion *const questi
q->nta = question->nta;
q->servAddr = question->servAddr;
q->servPort = question->servPort;
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ mdns_replace(&q->dnsservice, question->dnsservice);
+ mdns_forget(&question->dnsservice);
+ mdns_querier_forget(&q->querier);
+ mdns_replace(&q->querier, question->querier);
+ mdns_forget(&question->querier);
+#else
q->qDNSServer = question->qDNSServer;
q->validDNSServers = question->validDNSServers;
q->unansweredQueries = question->unansweredQueries;
q->noServerResponse = question->noServerResponse;
q->triedAllServersOnce = question->triedAllServersOnce;
+#endif
q->TargetQID = question->TargetQID;
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
q->LocalSocket = question->LocalSocket;
// No need to close old q->LocalSocket first -- duplicate questions can't have their own sockets
+#endif
q->state = question->state;
// q->tcp = question->tcp;
@@ -10849,13 +10819,16 @@ mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, DNSQuestion *const questi
q->ntries = question->ntries;
q->id = question->id;
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
question->LocalSocket = mDNSNULL;
+#endif
question->nta = mDNSNULL; // If we've got a GetZoneData in progress, transfer it to the newly active question
// question->tcp = mDNSNULL;
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
if (q->LocalSocket)
debugf("UpdateQuestionDuplicates transferred LocalSocket pointer for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
-
+#endif
if (q->nta)
{
LogInfo("UpdateQuestionDuplicates transferred nta pointer for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
@@ -10883,7 +10856,8 @@ mDNSexport McastResolver *mDNS_AddMcastResolver(mDNS *const m, const domainname
if (!d) d = (const domainname *)"";
- LogInfo("mDNS_AddMcastResolver: Adding %##s, InterfaceID %p, timeout %u", d->c, interface, timeout);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+ "mDNS_AddMcastResolver: Adding " PUB_DM_NAME ", InterfaceID %p, timeout %u", DM_NAME_PARAM(d), interface, timeout);
mDNS_CheckLock(m);
@@ -10905,7 +10879,7 @@ mDNSexport McastResolver *mDNS_AddMcastResolver(mDNS *const m, const domainname
else
{
// allocate, add to list
- *p = mDNSPlatformMemAllocate(sizeof(**p));
+ *p = (McastResolver *) mDNSPlatformMemAllocateClear(sizeof(**p));
if (!*p) LogMsg("mDNS_AddMcastResolver: ERROR!! - malloc");
else
{
@@ -10919,6 +10893,7 @@ mDNSexport McastResolver *mDNS_AddMcastResolver(mDNS *const m, const domainname
return(*p);
}
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
mDNSinline mDNSs32 PenaltyTimeForServer(mDNS *m, DNSServer *server)
{
mDNSs32 ptime = 0;
@@ -10938,6 +10913,7 @@ mDNSinline mDNSs32 PenaltyTimeForServer(mDNS *m, DNSServer *server)
}
return ptime;
}
+#endif
//Checks to see whether the newname is a better match for the name, given the best one we have
//seen so far (given in bestcount).
@@ -11046,17 +11022,18 @@ mDNSexport mDNSBool DomainEnumQuery(const domainname *qname)
return mDNStrue;
}
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
// Note: InterfaceID is the InterfaceID of the question
mDNSlocal mDNSBool DNSServerMatch(DNSServer *d, mDNSInterfaceID InterfaceID, mDNSs32 ServiceID)
{
- // 1) Unscoped questions (NULL InterfaceID) should consider *only* unscoped DNSServers ( DNSServer
- // with "scoped" set to kScopeNone)
+ // 1) Unscoped questions (NULL InterfaceID) should consider *only* unscoped DNSServers ( DNSServer
+ // with scopeType set to kScopeNone)
//
// 2) Scoped questions (non-NULL InterfaceID) should consider *only* scoped DNSServers (DNSServer
- // with "scoped" set to kScopeInterfaceId) and their InterfaceIDs should match.
+ // with scopeType set to kScopeInterfaceID) and their InterfaceIDs should match.
//
// 3) Scoped questions (non-zero ServiceID) should consider *only* scoped DNSServers (DNSServer
- // with "scoped" set to kScopeServiceID) and their ServiceIDs should match.
+ // with scopeType set to kScopeServiceID) and their ServiceIDs should match.
//
// The first condition in the "if" statement checks to see if both the question and the DNSServer are
// unscoped. The question is unscoped only if InterfaceID is zero and ServiceID is -1.
@@ -11073,13 +11050,10 @@ mDNSlocal mDNSBool DNSServerMatch(DNSServer *d, mDNSInterfaceID InterfaceID, mDN
//
// - DNSServer is scoped and InterfaceID is not NULL - the InterfaceID of the question and the DNSServer
// should match (Refer to (2) above).
- //
- // Note: mDNSInterface_Unicast is used only by .local unicast questions and are treated as unscoped.
- // If a question is scoped both to InterfaceID and ServiceID, the question will be scoped to InterfaceID.
- if (((d->scoped == kScopeNone) && ((!InterfaceID && ServiceID == -1) || InterfaceID == mDNSInterface_Unicast)) ||
- ((d->scoped == kScopeInterfaceID) && d->interface == InterfaceID) ||
- ((d->scoped == kScopeServiceID) && d->serviceID == ServiceID))
+ if (((d->scopeType == kScopeNone) && (!InterfaceID && ServiceID == -1)) ||
+ ((d->scopeType == kScopeInterfaceID) && d->interface == InterfaceID) ||
+ ((d->scopeType == kScopeServiceID) && d->serviceID == ServiceID))
{
return mDNStrue;
}
@@ -11100,11 +11074,11 @@ mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question)
DEQuery = DomainEnumQuery(&question->qname);
for (curr = m->DNSServers; curr; curr = curr->next)
{
- debugf("SetValidDNSServers: Parsing DNS server Address %#a (Domain %##s), Scope: %d", &curr->addr, curr->domain.c, curr->scoped);
+ debugf("SetValidDNSServers: Parsing DNS server Address %#a (Domain %##s), Scope: %d", &curr->addr, curr->domain.c, curr->scopeType);
// skip servers that will soon be deleted
- if (curr->flags & DNSServer_FlagDelete)
+ if (curr->flags & DNSServerFlag_Delete)
{
- debugf("SetValidDNSServers: Delete set for index %d, DNS server %#a (Domain %##s), scoped %d", index, &curr->addr, curr->domain.c, curr->scoped);
+ debugf("SetValidDNSServers: Delete set for index %d, DNS server %#a (Domain %##s), scoped %d", index, &curr->addr, curr->domain.c, curr->scopeType);
continue;
}
@@ -11117,16 +11091,16 @@ mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question)
// Note: DNS configuration change will help pick the new dns servers but currently it does not affect the timeout
// Skip DNSServers that are InterfaceID Scoped but have no valid interfaceid set OR DNSServers that are ServiceID Scoped but have no valid serviceid set
- if ((curr->scoped == kScopeInterfaceID && curr->interface == mDNSInterface_Any) || (curr->scoped == kScopeServiceID && curr->serviceID <= 0))
+ if (((curr->scopeType == kScopeInterfaceID) && (curr->interface == mDNSInterface_Any)) ||
+ ((curr->scopeType == kScopeServiceID) && (curr->serviceID <= 0)))
{
- LogInfo("SetValidDNSServers: ScopeType[%d] Skipping DNS server %#a (Domain %##s) Interface:[%p] Serviceid:[%d]", curr->scoped, &curr->addr, curr->domain.c, curr->interface, curr->serviceID);
+ LogInfo("SetValidDNSServers: ScopeType[%d] Skipping DNS server %#a (Domain %##s) Interface:[%p] Serviceid:[%d]",
+ (int)curr->scopeType, &curr->addr, curr->domain.c, curr->interface, curr->serviceID);
continue;
}
currcount = CountLabels(&curr->domain);
- if ((!curr->cellIntf || (!DEQuery && !(question->flags & kDNSServiceFlagsDenyCellular))) &&
- (!curr->isExpensive || !(question->flags & kDNSServiceFlagsDenyExpensive)) &&
- DNSServerMatch(curr, question->InterfaceID, question->ServiceID))
+ if ((!DEQuery || !curr->isCell) && DNSServerMatch(curr, question->InterfaceID, question->ServiceID))
{
bettermatch = BetterMatchForName(&question->qname, namecount, &curr->domain, currcount, bestmatchlen);
@@ -11144,11 +11118,11 @@ mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question)
timeout = 0;
}
debugf("SetValidDNSServers: question %##s Setting the bit for DNS server Address %#a (Domain %##s), Scoped:%d index %d,"
- " Timeout %d, interface %p", question->qname.c, &curr->addr, curr->domain.c, curr->scoped, index, curr->timeout,
+ " Timeout %d, interface %p", question->qname.c, &curr->addr, curr->domain.c, curr->scopeType, index, curr->timeout,
curr->interface);
timeout += curr->timeout;
if (DEQuery)
- debugf("DomainEnumQuery: Question %##s, DNSServer %#a, cell %d", question->qname.c, &curr->addr, curr->cellIntf);
+ debugf("DomainEnumQuery: Question %##s, DNSServer %#a, cell %d", question->qname.c, &curr->addr, curr->isCell);
bit_set_opaque128(question->validDNSServers, index);
}
}
@@ -11156,11 +11130,10 @@ mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question)
}
question->noServerResponse = 0;
- debugf("SetValidDNSServers: ValidDNSServer bits 0x%x%x%x%x for question %p %##s (%s)",
+ debugf("SetValidDNSServers: ValidDNSServer bits 0x%08x%08x%08x%08x for question %p %##s (%s)",
question->validDNSServers.l[3], question->validDNSServers.l[2], question->validDNSServers.l[1], question->validDNSServers.l[0], question, question->qname.c, DNSTypeName(question->qtype));
// If there are no matching resolvers, then use the default timeout value.
- // For ProxyQuestion, shorten the timeout so that dig does not timeout on us in case of no response.
- return ((question->ProxyQuestion || question->ValidatingResponse) ? DEFAULT_UDNSSEC_TIMEOUT : timeout ? timeout : DEFAULT_UDNS_TIMEOUT);
+ return (timeout ? timeout : DEFAULT_UDNS_TIMEOUT);
}
// Get the Best server that matches a name. If you find penalized servers, look for the one
@@ -11181,9 +11154,9 @@ mDNSlocal DNSServer *GetBestServer(mDNS *m, const domainname *name, mDNSInterfac
for (curr = m->DNSServers; curr; curr = curr->next)
{
// skip servers that will soon be deleted
- if (curr->flags & DNSServer_FlagDelete)
+ if (curr->flags & DNSServerFlag_Delete)
{
- debugf("GetBestServer: Delete set for index %d, DNS server %#a (Domain %##s), scoped %d", index, &curr->addr, curr->domain.c, curr->scoped);
+ debugf("GetBestServer: Delete set for index %d, DNS server %#a (Domain %##s), scoped %d", index, &curr->addr, curr->domain.c, curr->scopeType);
continue;
}
@@ -11246,7 +11219,7 @@ mDNSlocal DNSServer *GetServerForName(mDNS *m, const domainname *name, mDNSInter
char *ifname = mDNSNULL; // for logging purposes only
mDNSOpaque128 allValid;
- if ((InterfaceID == mDNSInterface_Unicast) || (InterfaceID == mDNSInterface_LocalOnly))
+ if (InterfaceID == mDNSInterface_LocalOnly)
InterfaceID = mDNSNULL;
if (InterfaceID) ifname = InterfaceNameForID(m, InterfaceID);
@@ -11275,7 +11248,7 @@ mDNSexport DNSServer *GetServerForQuestion(mDNS *m, DNSQuestion *question)
const domainname *name = &question->qname;
int currindex;
- if ((InterfaceID == mDNSInterface_Unicast) || (InterfaceID == mDNSInterface_LocalOnly))
+ if (InterfaceID == mDNSInterface_LocalOnly)
InterfaceID = mDNSNULL;
if (InterfaceID)
@@ -11290,23 +11263,23 @@ mDNSexport DNSServer *GetServerForQuestion(mDNS *m, DNSQuestion *question)
if (curmatch != mDNSNULL)
{
- LogInfo("GetServerForQuestion: %p DNS server (%p) %#a:%d (Penalty Time Left %d) (Scope %s:%p:%d) for %##s (%s)",
- question, curmatch, &curmatch->addr, mDNSVal16(curmatch->port),
- (curmatch->penaltyTime ? (curmatch->penaltyTime - m->timenow) : 0), ifname ? ifname : "None",
- InterfaceID, question->ServiceID, name, DNSTypeName(question->qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d->Q%d] GetServerForQuestion: %p DNS server (%p) " PRI_IP_ADDR ":%d (Penalty Time Left %d) (Scope " PUB_S ":%p:%d) for " PRI_DM_NAME " (" PUB_S ")",
+ question->request_id, mDNSVal16(question->TargetQID), question, curmatch, &curmatch->addr,
+ mDNSVal16(curmatch->port), (curmatch->penaltyTime ? (curmatch->penaltyTime - m->timenow) : 0),
+ ifname ? ifname : "None", InterfaceID, question->ServiceID, DM_NAME_PARAM(name), DNSTypeName(question->qtype));
}
else
{
- LogInfo("GetServerForQuestion: %p no DNS server (Scope %s:%p:%d) for %##s (%s)",
- question, ifname ? ifname : "None", InterfaceID, question->ServiceID, name, DNSTypeName(question->qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d->Q%d] GetServerForQuestion: %p no DNS server (Scope " PUB_S ":%p:%d) for " PRI_DM_NAME " (" PUB_S ")",
+ question->request_id, mDNSVal16(question->TargetQID), question, ifname ? ifname : "None", InterfaceID,
+ question->ServiceID, DM_NAME_PARAM(name), DNSTypeName(question->qtype));
}
return(curmatch);
}
-
-
-#define ValidQuestionTarget(Q) (((Q)->Target.type == mDNSAddrType_IPv4 || (Q)->Target.type == mDNSAddrType_IPv6) && \
- (mDNSSameIPPort((Q)->TargetPort, UnicastDNSPort) || mDNSSameIPPort((Q)->TargetPort, MulticastDNSPort)))
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
// Called in normal client context (lock not held)
mDNSlocal void LLQNATCallback(mDNS *m, NATTraversalInfo *n)
@@ -11318,221 +11291,165 @@ mDNSlocal void LLQNATCallback(mDNS *m, NATTraversalInfo *n)
for (q = m->Questions; q; q=q->next)
if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID) && q->LongLived)
startLLQHandshake(m, q); // If ExternalPort is zero, will do StartLLQPolling instead
-#if APPLE_OSX_mDNSResponder
- UpdateAutoTunnelDomainStatuses(m);
-#endif
mDNS_Unlock(m);
}
-mDNSlocal mDNSBool IsPrivateDomain(mDNS *const m, DNSQuestion *q)
-{
- DomainAuthInfo *AuthInfo;
- // Skip Private domains as we have special addresses to get the hosts in the Private domain
- AuthInfo = GetAuthInfoForName_internal(m, &q->qname);
- if (AuthInfo && !AuthInfo->deltime && AuthInfo->AutoTunnel)
- {
- debugf("IsPrivateDomain: %##s true", q->qname.c);
- return mDNStrue;
- }
- else
- {
- debugf("IsPrivateDomain: %##s false", q->qname.c);
- return mDNSfalse;
- }
-}
-
-#define TrueFalseStr(X) ((X) ? "true" : "false")
-
// This function takes the DNSServer as a separate argument because sometimes the
-// caller has not yet assigned the DNSServer, but wants to evaluate the SuppressQuery
+// caller has not yet assigned the DNSServer, but wants to evaluate the Suppressed
// status before switching to it.
-mDNSlocal mDNSBool ShouldSuppressUnicastQuery(mDNS *const m, DNSQuestion *q, DNSServer *d)
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+mDNSexport mDNSBool ShouldSuppressUnicastQuery(const DNSQuestion *const q, const mdns_dns_service_t dnsservice)
+#else
+mDNSlocal mDNSBool ShouldSuppressUnicastQuery(const DNSQuestion *const q, const DNSServer *const server)
+#endif
{
- // Some callers don't check for the qtype
- if (q->qtype != kDNSType_A && q->qtype != kDNSType_AAAA)
- {
- LogDebug("ShouldSuppressUnicastQuery: Query not suppressed for %##s, qtype %s, not A/AAAA type", q->qname.c, DNSTypeName(q->qtype));
- return mDNSfalse;
- }
+ mDNSBool suppress = mDNSfalse;
+ const char *reason = mDNSNULL;
- // Private domains are exempted irrespective of what the DNSServer says
- if (IsPrivateDomain(m, q))
+ if (q->BlockedByPolicy)
{
- LogDebug("ShouldSuppressUnicastQuery: Query not suppressed for %##s, qtype %s, Private Domain", q->qname.c, DNSTypeName(q->qtype));
- return mDNSfalse;
- }
-
- if (!d)
- {
- LogInfo("ShouldSuppressUnicastQuery: Query suppressed for %##s, qtype %s, as the DNS server is NULL", q->qname.c, DNSTypeName(q->qtype));
- return mDNStrue;
+ suppress = mDNStrue;
+ reason = " (blocked by policy)";
}
-
- // Check if the DNS Configuration allows A/AAAA queries to be sent
- if ((q->qtype == kDNSType_A) && d->req_A)
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ else if (!dnsservice)
{
- // The server's configuration allows A record queries, so don't suppress this query unless
- // 1. the interface associated with the server is CLAT46; and
- // 2. the query has the kDNSServiceFlagsPathEvaluationDone flag, which indicates that it came from libnetcore.
- // See <rdar://problem/42672030> for more info.
- if (!(d->isCLAT46 && (q->flags & kDNSServiceFlagsPathEvaluationDone)))
+ if (!q->IsUnicastDotLocal)
{
- LogDebug("ShouldSuppressUnicastQuery: Query not suppressed for %##s, qtype %s, DNSServer %##s %#a:%d allows A queries", q->qname.c,
- DNSTypeName(q->qtype), d->domain.c, &d->addr, mDNSVal16(d->port));
- return mDNSfalse;
+ suppress = mDNStrue;
+ reason = " (no DNS service)";
}
}
- if ((q->qtype == kDNSType_AAAA) && d->req_AAAA)
+#else
+ else if (!server)
{
- LogDebug("ShouldSuppressUnicastQuery: Query not suppressed for %##s, qtype %s, DNSServer %##s %#a:%d allows AAAA queries", q->qname.c,
- DNSTypeName(q->qtype), d->domain.c, &d->addr, mDNSVal16(d->port));
- return mDNSfalse;
+ if (!q->IsUnicastDotLocal)
+ {
+ suppress = mDNStrue;
+ reason = " (no DNS server)";
+ }
}
-#if USE_DNS64
- if (DNS64IsQueryingARecord(q->dns64.state))
+#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ else if ((q->flags & kDNSServiceFlagsDenyCellular) && mdns_dns_service_interface_is_cellular(dnsservice))
+#else
+ else if ((q->flags & kDNSServiceFlagsDenyCellular) && server->isCell)
+#endif
{
- LogDebug("ShouldSuppressUnicastQuery: DNS64 query not suppressed for %##s, qtype %s", q->qname.c, DNSTypeName(q->qtype));
- return mDNSfalse;
+ suppress = mDNStrue;
+ reason = " (interface is cellular)";
}
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ else if ((q->flags & kDNSServiceFlagsDenyExpensive) && mdns_dns_service_interface_is_expensive(dnsservice))
+#else
+ else if ((q->flags & kDNSServiceFlagsDenyExpensive) && server->isExpensive)
#endif
-
- LogInfo("ShouldSuppressUnicastQuery: Query suppressed for %##s, qtype %s, since DNS Configuration does not allow (req_A %s, req_AAAA %s, CLAT46 %s)",
- q->qname.c, DNSTypeName(q->qtype), TrueFalseStr(d->req_A), TrueFalseStr(d->req_AAAA), TrueFalseStr(d->isCLAT46));
-
- return mDNStrue;
-}
-
-mDNSlocal mDNSBool ShouldSuppressDotLocalQuery(mDNS *const m, DNSQuestion *q)
-{
- NetworkInterfaceInfo *intf;
- AuthRecord *rr;
- mDNSBool ret;
-
- // Check to see if there is at least one interface other than loopback and don't suppress
- // .local questions if you find one. If we have at least one interface, it means that
- // we can send unicast queries for the .local name and we don't want to suppress
- // multicast in that case as upper layers don't know how to handle if we return a
- // negative response for multicast followed by a positive response for unicast.
- //
- // Note: we used to check for multicast capable interfaces instead of just any interface
- // present. That did not work in the case where we have a valid interface for unicast
- // but not multicast capable e.g., cellular, as we ended up delivering a negative response
- // first and the upper layer did not wait for the positive response that came later.
- for (intf = m->HostInterfaces; intf; intf = intf->next)
{
- if (intf->InterfaceActive && !intf->Loopback)
- {
- LogInfo("ShouldSuppressDotLocalQuery: Found interface %s, not suppressing", intf->ifname);
- return mDNSfalse;
- }
+ suppress = mDNStrue;
+ reason = " (interface is expensive)";
}
-
- // 1. If we find a LocalOnly or P2P record answering this question, then don't suppress it.
- // Set m->CurrentQuestion as it is required by AnswerQuestionWithLORecord.
- m->CurrentQuestion = q;
- ret = AnswerQuestionWithLORecord(m, q, mDNStrue);
- m->CurrentQuestion = mDNSNULL;
-
- if (ret)
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ else if ((q->flags & kDNSServiceFlagsDenyConstrained) && mdns_dns_service_interface_is_constrained(dnsservice))
+#else
+ else if ((q->flags & kDNSServiceFlagsDenyConstrained) && server->isConstrained)
+#endif
{
- LogInfo("ShouldSuppressDotLocalQuery: Found LocalOnly record for %##s (%s), not suppressing", q->qname.c,
- DNSTypeName(q->qtype));
- return mDNSfalse;
+ suppress = mDNStrue;
+ reason = " (interface is constrained)";
}
-
- // 2. If we find a local AuthRecord answering this question, then don't suppress it.
- for (rr = m->ResourceRecords; rr; rr = rr->next)
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
+ else if (q->SuppressUnusable && !DNS64IsQueryingARecord(q->dns64.state))
+#else
+ else if (q->SuppressUnusable)
+#endif
{
- if (ResourceRecordAnswersQuestion(&rr->resrec, q))
+ if (q->qtype == kDNSType_A)
+ {
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ if (!mdns_dns_service_a_queries_advised(dnsservice))
+#else
+ if (!server->usableA)
+#endif
+ {
+ suppress = mDNStrue;
+ reason = " (A records are unusable)";
+ }
+ // If the server's configuration allows A record queries, suppress this query if
+ // 1. the interface associated with the server is CLAT46; and
+ // 2. the query has the kDNSServiceFlagsPathEvaluationDone flag, indicating that it's from libnetwork.
+ // See <rdar://problem/42672030> for more info.
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ else if ((q->flags & kDNSServiceFlagsPathEvaluationDone) && mdns_dns_service_interface_is_clat46(dnsservice))
+#else
+ else if ((q->flags & kDNSServiceFlagsPathEvaluationDone) && server->isCLAT46)
+#endif
+ {
+ suppress = mDNStrue;
+ reason = " (CLAT46 A records are unusable)";
+ }
+ }
+ else if (q->qtype == kDNSType_AAAA)
{
- LogInfo("ShouldSuppressDotLocalQuery: Found resource record %s for %##s (%s) not suppressing", ARDisplayString(m, rr),
- q->qname.c, DNSTypeName(q->qtype));
- return mDNSfalse;
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ if (!mdns_dns_service_aaaa_queries_advised(dnsservice))
+#else
+ if (!server->usableAAAA)
+#endif
+ {
+ suppress = mDNStrue;
+ reason = " (AAAA records are unusable)";
+ }
}
}
- return mDNStrue;
-}
-
-mDNSlocal mDNSBool ShouldSuppressQuery(mDNS *const m, DNSQuestion *q)
-{
- if (q->InterfaceID == mDNSInterface_LocalOnly)
+ if (suppress)
{
- LogInfo("ShouldSuppressQuery: LocalOnly query not suppressed for %##s, qtype %s", q->qname.c, DNSTypeName(q->qtype));
- return mDNSfalse;
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[Q%u] ShouldSuppressUnicastQuery: Query suppressed for " PRI_DM_NAME " " PUB_S PUB_S,
+ mDNSVal16(q->TargetQID), DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype), reason ? reason : "");
}
+ return suppress;
+}
- if (q->qtype != kDNSType_A && q->qtype != kDNSType_AAAA)
+mDNSlocal mDNSBool ShouldSuppressQuery(DNSQuestion *q)
+{
+ // Multicast queries are never suppressed.
+ if (mDNSOpaque16IsZero(q->TargetQID))
{
- LogInfo("ShouldSuppressQuery: Query not suppressed for %##s, qtype %s, not A/AAAA type", q->qname.c, DNSTypeName(q->qtype));
return mDNSfalse;
}
-
- // We still want the ability to be able to listen to the local services and hence
- // don't fail .local query if we have local records that can potentially answer
- // the question.
- if (q->InterfaceID != mDNSInterface_Unicast && IsLocalDomain(&q->qname))
- {
- if (!ShouldSuppressDotLocalQuery(m, q))
- {
- LogInfo("ShouldSuppressQuery: Query not suppressed for %##s, qtype %s, Local question", q->qname.c, DNSTypeName(q->qtype));
- return mDNSfalse;
- }
- else
- {
- LogInfo("ShouldSuppressQuery: Query suppressed for %##s, qtype %s, Local question", q->qname.c, DNSTypeName(q->qtype));
- return mDNStrue;
- }
- }
-
- return (ShouldSuppressUnicastQuery(m, q, q->qDNSServer));
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ return (ShouldSuppressUnicastQuery(q, q->dnsservice));
+#else
+ return (ShouldSuppressUnicastQuery(q, q->qDNSServer));
+#endif
}
mDNSlocal void CacheRecordRmvEventsForCurrentQuestion(mDNS *const m, DNSQuestion *q)
{
- CacheRecord *rr;
+ CacheRecord *cr;
CacheGroup *cg;
cg = CacheGroupForName(m, q->qnamehash, &q->qname);
- for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
+ for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
{
// Don't deliver RMV events for negative records
- if (rr->resrec.RecordType == kDNSRecordTypePacketNegative)
+ if (cr->resrec.RecordType == kDNSRecordTypePacketNegative)
{
- LogInfo("CacheRecordRmvEventsForCurrentQuestion: CacheRecord %s Suppressing RMV events for question %p %##s (%s), CRActiveQuestion %p, CurrentAnswers %d",
- CRDisplayString(m, rr), q, q->qname.c, DNSTypeName(q->qtype), rr->CRActiveQuestion, q->CurrentAnswers);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] CacheRecordRmvEventsForCurrentQuestion: CacheRecord " PRI_S " Suppressing RMV events for question %p " PRI_DM_NAME " (" PUB_S "), CRActiveQuestion %p, CurrentAnswers %d",
+ q->request_id, mDNSVal16(q->TargetQID), CRDisplayString(m, cr), q, DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype), cr->CRActiveQuestion, q->CurrentAnswers);
continue;
}
- if (SameNameRecordAnswersQuestion(&rr->resrec, q))
+ if (SameNameCacheRecordAnswersQuestion(cr, q))
{
LogInfo("CacheRecordRmvEventsForCurrentQuestion: Calling AnswerCurrentQuestionWithResourceRecord (RMV) for question %##s using resource record %s LocalAnswers %d",
- q->qname.c, CRDisplayString(m, rr), q->LOAddressAnswers);
+ q->qname.c, CRDisplayString(m, cr), q->LOAddressAnswers);
q->CurrentAnswers--;
- if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers--;
- if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers--;
-
- if (rr->CRActiveQuestion == q)
- {
- DNSQuestion *qptr;
- // If this was the active question for this cache entry, it was the one that was
- // responsible for keeping the cache entry fresh when the cache entry was reaching
- // its expiry. We need to handover the responsibility to someone else. Otherwise,
- // when the cache entry is about to expire, we won't find an active question
- // (pointed by CRActiveQuestion) to refresh the cache.
- for (qptr = m->Questions; qptr; qptr=qptr->next)
- if (qptr != q && ActiveQuestion(qptr) && ResourceRecordAnswersQuestion(&rr->resrec, qptr))
- break;
-
- if (qptr)
- LogInfo("CacheRecordRmvEventsForCurrentQuestion: Updating CRActiveQuestion to %p for cache record %s, "
- "Original question CurrentAnswers %d, new question CurrentAnswers %d, SuppressUnusable %d, SuppressQuery %d",
- qptr, CRDisplayString(m,rr), q->CurrentAnswers, qptr->CurrentAnswers, qptr->SuppressUnusable, qptr->SuppressQuery);
-
- rr->CRActiveQuestion = qptr; // Question used to be active; new value may or may not be null
- if (!qptr) m->rrcache_active--; // If no longer active, decrement rrcache_active count
- }
- AnswerCurrentQuestionWithResourceRecord(m, rr, QC_rmv);
+ if (cr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers--;
+ if (cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers--;
+ AnswerCurrentQuestionWithResourceRecord(m, cr, QC_rmv);
if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here
}
}
@@ -11546,7 +11463,11 @@ mDNSlocal mDNSBool IsQuestionNew(mDNS *const m, DNSQuestion *question)
return mDNSfalse;
}
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+mDNSexport mDNSBool LocalRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q)
+#else
mDNSlocal mDNSBool LocalRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q)
+#endif
{
AuthRecord *rr;
AuthGroup *ag;
@@ -11611,24 +11532,28 @@ mDNSlocal void SuppressStatusChanged(mDNS *const m, DNSQuestion *q, DNSQuestion
// NOTE: CacheRecordRmvEventsForQuestion will not generate RMV events for queries that have non-zero
// LOAddressAnswers. Hence it is important that we call CacheRecordRmvEventsForQuestion before
// LocalRecordRmvEventsForQuestion (which decrements LOAddressAnswers)
- if (q->SuppressQuery)
+ if (q->Suppressed)
{
- q->SuppressQuery = mDNSfalse;
+ q->Suppressed = mDNSfalse;
if (!CacheRecordRmvEventsForQuestion(m, q))
{
- LogInfo("SuppressStatusChanged: Question deleted while delivering RMV events from cache");
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] SuppressStatusChanged: Question deleted while delivering RMV events from cache",
+ q->request_id, mDNSVal16(q->TargetQID));
return;
}
- q->SuppressQuery = mDNStrue;
+ q->Suppressed = mDNStrue;
}
// SuppressUnusable does not affect questions that are answered from the local records (/etc/hosts)
- // and SuppressQuery status does not mean anything for these questions. As we are going to stop the
+ // and Suppressed status does not mean anything for these questions. As we are going to stop the
// question below, we need to deliver the RMV events so that the ADDs that will be delivered during
// the restart will not be a duplicate ADD
if (!LocalRecordRmvEventsForQuestion(m, q))
{
- LogInfo("SuppressStatusChanged: Question deleted while delivering RMV events from Local AuthRecords");
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] SuppressStatusChanged: Question deleted while delivering RMV events from Local AuthRecords",
+ q->request_id, mDNSVal16(q->TargetQID));
return;
}
@@ -11642,9 +11567,9 @@ mDNSlocal void SuppressStatusChanged(mDNS *const m, DNSQuestion *q, DNSQuestion
//
// 2. Previously it was not suppressed and now it is suppressed. We need to restart the questions
// so that we redo the duplicate checks in mDNS_StartQuery_internal. A SuppressUnusable question
- // is a duplicate of non-SuppressUnusable question if it is not suppressed (SuppressQuery is false).
+ // is a duplicate of non-SuppressUnusable question if it is not suppressed (Suppressed is false).
// A SuppressUnusable question is not a duplicate of non-SuppressUnusable question if it is suppressed
- // (SuppressQuery is true). The reason for this is that when a question is suppressed, we want an
+ // (Suppressed is true). The reason for this is that when a question is suppressed, we want an
// immediate response and not want to be blocked behind a question that is querying DNS servers. When
// the question is not suppressed, we don't want two active questions sending packets on the wire.
// This affects both efficiency and also the current design where there is only one active question
@@ -11659,7 +11584,9 @@ mDNSlocal void SuppressStatusChanged(mDNS *const m, DNSQuestion *q, DNSQuestion
//
// It is much cleaner and less error prone to build a list of questions and restart at the end.
- LogInfo("SuppressStatusChanged: Stop question %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] SuppressStatusChanged: Stop question %p " PRI_DM_NAME " (" PUB_S ")",
+ q->request_id, mDNSVal16(q->TargetQID), q, DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype));
mDNS_StopQuery_internal(m, q);
q->next = *restart;
*restart = q;
@@ -11675,7 +11602,7 @@ mDNSexport void CheckSuppressUnusableQuestions(mDNS *const m)
// we potentially restart questions here in this function that ends up as new questions,
// which may be suppressed at this instance. Before it is handled we get another network
// event that changes the status e.g., address becomes available. If we did not process
- // new questions, we would never change its SuppressQuery status.
+ // new questions, we would never change its Suppressed status.
//
// CurrentQuestion is used by RmvEventsForQuestion below. While delivering RMV events, the
// application callback can potentially stop the current question (detected by CurrentQuestion) or
@@ -11692,9 +11619,9 @@ mDNSexport void CheckSuppressUnusableQuestions(mDNS *const m)
m->RestartQuestion = q->next;
if (q->SuppressUnusable)
{
- mDNSBool old = q->SuppressQuery;
- q->SuppressQuery = ShouldSuppressQuery(m, q);
- if (q->SuppressQuery != old)
+ const mDNSBool old = q->Suppressed;
+ q->Suppressed = ShouldSuppressQuery(q);
+ if (q->Suppressed != old)
{
// Previously it was not suppressed, Generate RMV events for the ADDs that we might have delivered before
// followed by a negative cache response. Temporarily turn off suppression so that
@@ -11713,10 +11640,11 @@ mDNSexport void CheckSuppressUnusableQuestions(mDNS *const m)
}
}
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
mDNSlocal void RestartUnicastQuestions(mDNS *const m)
{
DNSQuestion *q;
- DNSQuestion *restart = mDNSNULL;
+ DNSQuestion *restartList = mDNSNULL;
if (m->RestartQuestion)
LogMsg("RestartUnicastQuestions: ERROR!! m->RestartQuestion already set: %##s (%s)",
@@ -11731,50 +11659,39 @@ mDNSlocal void RestartUnicastQuestions(mDNS *const m)
if (mDNSOpaque16IsZero(q->TargetQID))
LogMsg("RestartUnicastQuestions: ERROR!! Restart set for multicast question %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- q->Restart = 0;
- SuppressStatusChanged(m, q, &restart);
+ q->Restart = mDNSfalse;
+ SuppressStatusChanged(m, q, &restartList);
}
}
- while (restart)
+ while ((q = restartList) != mDNSNULL)
{
- q = restart;
- restart = restart->next;
+ restartList = q->next;
q->next = mDNSNULL;
- LogInfo("RestartUnicastQuestions: Start question %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] RestartUnicastQuestions: Start question %p " PRI_DM_NAME " (" PUB_S ")",
+ q->request_id, mDNSVal16(q->TargetQID), q, DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype));
mDNS_StartQuery_internal(m, q);
}
}
-
+#endif
// ValidateParameters() is called by mDNS_StartQuery_internal() to check the client parameters of
// DNS Question that are already set by the client before calling mDNS_StartQuery()
mDNSlocal mStatus ValidateParameters(mDNS *const m, DNSQuestion *const question)
{
-
- if (question->Target.type && !ValidQuestionTarget(question))
- {
- LogMsg("ValidateParameters: Warning! Target.type = %ld port = %u (Client forgot to initialize before calling mDNS_StartQuery? for question %##s)",
- question->Target.type, mDNSVal16(question->TargetPort), question->qname.c);
- question->Target.type = mDNSAddrType_None;
- }
-
- // If no question->Target specified, clear TargetPort
- if (!question->Target.type)
- question->TargetPort = zeroIPPort;
-
if (!ValidateDomainName(&question->qname))
{
LogMsg("ValidateParameters: Attempt to start query with invalid qname %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
return(mStatus_Invalid);
}
- // If this question is referencing a specific interface, verify it exists
- if (question->InterfaceID && !LocalOnlyOrP2PInterface(question->InterfaceID) && question->InterfaceID != mDNSInterface_Unicast)
+ // If this question is referencing a specific interface, verify it exists
+ if (question->InterfaceID && !LocalOnlyOrP2PInterface(question->InterfaceID))
{
NetworkInterfaceInfo *intf = FirstInterfaceForID(m, question->InterfaceID);
if (!intf)
LogInfo("ValidateParameters: Note: InterfaceID %d for question %##s (%s) not currently found in active interface list",
- (uint32_t)question->InterfaceID, question->qname.c, DNSTypeName(question->qtype));
+ IIDPrintable(question->InterfaceID), question->qname.c, DNSTypeName(question->qtype));
}
return(mStatus_NoError);
@@ -11785,12 +11702,16 @@ mDNSlocal mStatus ValidateParameters(mDNS *const m, DNSQuestion *const question)
mDNSlocal void InitDNSConfig(mDNS *const m, DNSQuestion *const question)
{
// First reset all DNS Configuration
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ mdns_forget(&question->dnsservice);
+#else
question->qDNSServer = mDNSNULL;
question->validDNSServers = zeroOpaque128;
- question->triedAllServersOnce = 0;
- question->noServerResponse = 0;
+ question->triedAllServersOnce = mDNSfalse;
+ question->noServerResponse = mDNSfalse;
+#endif
question->StopTime = (question->TimeoutQuestion) ? question->StopTime : 0;
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
mDNSPlatformMemZero(&question->metrics, sizeof(question->metrics));
question->metrics.expiredAnswerState = (question->allowExpired != AllowExpired_None) ? ExpiredAnswer_Allowed : ExpiredAnswer_None;
#endif
@@ -11801,7 +11722,11 @@ mDNSlocal void InitDNSConfig(mDNS *const m, DNSQuestion *const question)
// Proceed to initialize DNS Configuration (some are set in SetValidDNSServers())
if (!mDNSOpaque16IsZero(question->TargetQID))
{
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ mDNSu32 timeout = 30;
+#else
mDNSu32 timeout = SetValidDNSServers(m, question);
+#endif
// We set the timeout value the first time mDNS_StartQuery_internal is called for a question.
// So if a question is restarted when a network change occurs, the StopTime is not reset.
// Note that we set the timeout for all questions. If this turns out to be a duplicate,
@@ -11809,14 +11734,21 @@ mDNSlocal void InitDNSConfig(mDNS *const m, DNSQuestion *const question)
if (question->TimeoutQuestion && !question->StopTime)
{
question->StopTime = NonZeroTime(m->timenow + timeout * mDNSPlatformOneSecond);
- LogInfo("InitDNSConfig: Setting StopTime on the uDNS question %p %##s (%s)", question, question->qname.c, DNSTypeName(question->qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[Q%u] InitDNSConfig: Setting StopTime on the uDNS question %p " PRI_DM_NAME " (" PUB_S ")",
+ mDNSVal16(question->TargetQID), question, DM_NAME_PARAM(&question->qname), DNSTypeName(question->qtype));
}
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ Querier_SetDNSServiceForQuestion(question);
+#else
question->qDNSServer = GetServerForQuestion(m, question);
- LogDebug("InitDNSConfig: question %p %##s (%s) Timeout %d, DNS Server %#a:%d",
- question, question->qname.c, DNSTypeName(question->qtype), timeout,
- question->qDNSServer ? &question->qDNSServer->addr : mDNSNULL,
- mDNSVal16(question->qDNSServer ? question->qDNSServer->port : zeroIPPort));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+ "[R%u->Q%u] InitDNSConfig: question %p " PRI_DM_NAME " " PUB_S " Timeout %d, DNS Server " PRI_IP_ADDR ":%d",
+ question->request_id, mDNSVal16(question->TargetQID), question, DM_NAME_PARAM(&question->qname),
+ DNSTypeName(question->qtype), timeout, question->qDNSServer ? &question->qDNSServer->addr : mDNSNULL,
+ mDNSVal16(question->qDNSServer ? question->qDNSServer->port : zeroIPPort));
+#endif
}
else if (question->TimeoutQuestion && !question->StopTime)
{
@@ -11825,7 +11757,9 @@ mDNSlocal void InitDNSConfig(mDNS *const m, DNSQuestion *const question)
mDNSu32 timeout = LocalOnlyOrP2PInterface(question->InterfaceID) ?
DEFAULT_LO_OR_P2P_TIMEOUT : GetTimeoutForMcastQuestion(m, question);
question->StopTime = NonZeroTime(m->timenow + timeout * mDNSPlatformOneSecond);
- LogInfo("InitDNSConfig: Setting StopTime on question %p %##s (%s)", question, question->qname.c, DNSTypeName(question->qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] InitDNSConfig: Setting StopTime on the uDNS question %p " PRI_DM_NAME " (" PUB_S ")",
+ question->request_id, mDNSVal16(question->TargetQID), question, DM_NAME_PARAM(&question->qname), DNSTypeName(question->qtype));
}
// Set StopTime here since it is a part of DNS Configuration
if (question->StopTime)
@@ -11841,7 +11775,6 @@ mDNSlocal void InitDNSConfig(mDNS *const m, DNSQuestion *const question)
mDNSlocal void InitCommonState(mDNS *const m, DNSQuestion *const question)
{
int i;
- mDNSBool isBlocked = mDNSfalse;
// Note: In the case where we already have the answer to this question in our cache, that may be all the client
// wanted, and they may immediately cancel their question. In this case, sending an actual query on the wire would
@@ -11855,7 +11788,7 @@ mDNSlocal void InitCommonState(mDNS *const m, DNSQuestion *const question)
// stopped and can't be on the list. The question is already on the list and ThisQInterval
// can be negative if the caller just stopped it and starting it again. Hence, it always has to
// be initialized. CheckForSoonToExpireRecords below prints the cache records when logging is
- // turned ON which can allocate memory e.g., base64 encoding, in the case of DNSSEC.
+ // turned ON which can allocate memory e.g., base64 encoding.
question->ThisQInterval = InitialQuestionInterval; // MUST be > zero for an active question
question->qnamehash = DomainNameHashValue(&question->qname);
question->DelayAnswering = mDNSOpaque16IsZero(question->TargetQID) ? CheckForSoonToExpireRecords(m, &question->qname, question->qnamehash) : 0;
@@ -11890,14 +11823,26 @@ mDNSlocal void InitCommonState(mDNS *const m, DNSQuestion *const question)
question->FlappingInterface1 = mDNSNULL;
question->FlappingInterface2 = mDNSNULL;
+ // mDNSPlatformGetDNSRoutePolicy() and InitDNSConfig() may set a DNSQuestion's BlockedByPolicy value,
+ // so they should be called before calling ShouldSuppressQuery(), which checks BlockedByPolicy.
+ question->BlockedByPolicy = mDNSfalse;
+
// if kDNSServiceFlagsServiceIndex flag is SET by the client, then do NOT call mDNSPlatformGetDNSRoutePolicy()
// since we would already have the question->ServiceID in that case.
if (!(question->flags & kDNSServiceFlagsServiceIndex))
{
-#if APPLE_OSX_mDNSResponder
- mDNSPlatformGetDNSRoutePolicy(question, &isBlocked);
-#else
question->ServiceID = -1;
+#if APPLE_OSX_mDNSResponder
+ if (!(question->flags & kDNSServiceFlagsPathEvaluationDone) || question->ForcePathEval)
+ {
+ if (question->flags & kDNSServiceFlagsPathEvaluationDone)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] Forcing another path evaluation", question->request_id, mDNSVal16(question->TargetQID));
+ }
+ question->ForcePathEval = mDNSfalse;
+ mDNSPlatformGetDNSRoutePolicy(question);
+ }
#endif
}
else
@@ -11905,19 +11850,8 @@ mDNSlocal void InitCommonState(mDNS *const m, DNSQuestion *const question)
DNSTypeName(question->qtype), question->pid, question->euid, question->ServiceID);
InitDNSConfig(m, question);
-
question->AuthInfo = GetAuthInfoForQuestion(m, question);
- question->SuppressQuery = 0;
- if (question->SuppressUnusable)
- question->SuppressQuery = ShouldSuppressQuery(m, question);
-
- // If ServiceID is 0 or the policy disallows making DNS requests,
- // set DisallowPID
- question->DisallowPID = (question->ServiceID == 0 || isBlocked);
- if (question->DisallowPID)
- LogInfo("InitCommonState: Query suppressed for %##s (%s), PID %d/ServiceID %d not allowed", question->qname.c,
- DNSTypeName(question->qtype), question->pid, question->ServiceID);
-
+ question->Suppressed = ShouldSuppressQuery(question);
question->NextInDQList = mDNSNULL;
question->SendQNow = mDNSNULL;
question->SendOnAll = mDNSfalse;
@@ -11945,7 +11879,9 @@ mDNSlocal void InitCommonState(mDNS *const m, DNSQuestion *const question)
for (i=0; i<DupSuppressInfoSize; i++)
question->DupSuppress[i].InterfaceID = mDNSNULL;
- question->Restart = 0;
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ question->Restart = mDNSfalse;
+#endif
debugf("InitCommonState: Question %##s (%s) Interface %p Now %d Send in %d Answer in %d (%p) %s (%p)",
question->qname.c, DNSTypeName(question->qtype), question->InterfaceID, m->timenow,
@@ -11966,7 +11902,11 @@ mDNSlocal void InitWABState(DNSQuestion *const question)
// We also don't need one for LLQs because (when we're using NAT) we want them all to share a single
// NAT mapping for receiving inbound add/remove events.
question->LocalSocket = mDNSNULL;
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ mdns_querier_forget(&question->querier);
+#else
question->unansweredQueries = 0;
+#endif
question->nta = mDNSNULL;
question->servAddr = zeroAddr;
question->servPort = zeroIPPort;
@@ -11990,48 +11930,19 @@ mDNSlocal void InitLLQNATState(mDNS *const m)
mDNSlocal void InitLLQState(DNSQuestion *const question)
{
- question->state = LLQ_InitialRequest;
+ question->state = LLQ_Init;
question->ReqLease = 0;
question->expire = 0;
question->ntries = 0;
question->id = zeroOpaque64;
}
-#ifdef DNS_PUSH_ENABLED
-mDNSlocal void InitDNSPNState(DNSQuestion *const question)
-{
- question->dnsPushState = DNSPUSH_INIT;
-}
-#endif // DNS_PUSH_ENABLED
-
// InitDNSSECProxyState() is called by mDNS_StartQuery_internal() to initialize
// DNSSEC & DNS Proxy fields of the DNS Question.
mDNSlocal void InitDNSSECProxyState(mDNS *const m, DNSQuestion *const question)
{
(void) m;
-
- // DNS server selection affects DNSSEC. Turn off validation if req_DO is not set
- // or the request is going over cellular interface.
- //
- // Note: This needs to be done here before we call FindDuplicateQuestion as it looks
- // at ValidationRequired setting also.
- if (question->qDNSServer)
- {
- if (question->qDNSServer->cellIntf)
- {
- debugf("InitDNSSECProxyState: Turning off validation for %##s (%s); going over cell", question->qname.c, DNSTypeName(question->qtype));
- question->ValidationRequired = mDNSfalse;
- }
- if (DNSSECOptionalQuestion(question) && !(question->qDNSServer->req_DO))
- {
- LogInfo("InitDNSSECProxyState: Turning off validation for %##s (%s); req_DO false",
- question->qname.c, DNSTypeName(question->qtype));
- question->ValidationRequired = DNSSEC_VALIDATION_NONE;
- }
- }
- question->ValidationState = (question->ValidationRequired ? DNSSECValRequired : DNSSECValNotRequired);
- question->ValidationStatus = 0;
- question->responseFlags = zeroID;
+ question->responseFlags = zeroID;
}
// Once the question is completely initialized including the duplicate logic, this function
@@ -12042,31 +11953,41 @@ mDNSlocal void FinalizeUnicastQuestion(mDNS *const m, DNSQuestion *question)
// Ensure DNS related info of duplicate question is same as the orig question
if (question->DuplicateOf)
{
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ const DNSQuestion *const duplicateOf = question->DuplicateOf;
+ mdns_replace(&question->dnsservice, duplicateOf->dnsservice);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->DupQ%u->Q%u] Duplicate question " PRI_DM_NAME " (" PUB_S ")",
+ question->request_id, mDNSVal16(question->TargetQID), mDNSVal16(duplicateOf->TargetQID),
+ DM_NAME_PARAM(&question->qname), DNSTypeName(question->qtype));
+#else
question->validDNSServers = question->DuplicateOf->validDNSServers;
// If current(dup) question has DNS Server assigned but the original question has no DNS Server assigned to it,
// then we log a line as it could indicate an issue
if (question->DuplicateOf->qDNSServer == mDNSNULL)
{
if (question->qDNSServer)
- LogInfo("FinalizeUnicastQuestion: Current(dup) question %p has DNSServer(%#a:%d) but original question(%p) has no DNS Server! %##s (%s)",
- question, question->qDNSServer ? &question->qDNSServer->addr : mDNSNULL,
- mDNSVal16(question->qDNSServer ? question->qDNSServer->port : zeroIPPort),
- question->DuplicateOf, question->qname.c, DNSTypeName(question->qtype));
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d->Q%d] FinalizeUnicastQuestion: Current(dup) question %p has DNSServer(" PRI_IP_ADDR ":%d) but original question(%p) has no DNS Server! " PRI_DM_NAME " (" PUB_S ")",
+ question->request_id, mDNSVal16(question->TargetQID), question,
+ question->qDNSServer ? &question->qDNSServer->addr : mDNSNULL,
+ mDNSVal16(question->qDNSServer ? question->qDNSServer->port : zeroIPPort), question->DuplicateOf,
+ DM_NAME_PARAM(&question->qname), DNSTypeName(question->qtype));
+ }
}
question->qDNSServer = question->DuplicateOf->qDNSServer;
- LogInfo("FinalizeUnicastQuestion: Duplicate question %p (%p) %##s (%s), DNS Server %#a:%d",
- question, question->DuplicateOf, question->qname.c, DNSTypeName(question->qtype),
- question->qDNSServer ? &question->qDNSServer->addr : mDNSNULL,
- mDNSVal16(question->qDNSServer ? question->qDNSServer->port : zeroIPPort));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d->DupQ%d->Q%d] FinalizeUnicastQuestion: Duplicate question %p (%p) " PRI_DM_NAME " (" PUB_S "), DNS Server " PRI_IP_ADDR ":%d",
+ question->request_id, mDNSVal16(question->TargetQID), mDNSVal16(question->DuplicateOf->TargetQID),
+ question, question->DuplicateOf, DM_NAME_PARAM(&question->qname), DNSTypeName(question->qtype),
+ question->qDNSServer ? &question->qDNSServer->addr : mDNSNULL,
+ mDNSVal16(question->qDNSServer ? question->qDNSServer->port : zeroIPPort));
+#endif
}
ActivateUnicastQuery(m, question, mDNSfalse);
- if (!question->DuplicateOf && DNSSECQuestion(question))
- {
- // For DNSSEC questions, we need to have the RRSIGs also for verification.
- CheckForDNSSECRecords(m, question);
- }
if (question->LongLived)
{
// Unlike other initializations, InitLLQNATState should be done after
@@ -12075,9 +11996,6 @@ mDNSlocal void FinalizeUnicastQuestion(mDNS *const m, DNSQuestion *question)
// the LLQ NAT state only for unicast. Otherwise we will unnecessarily
// start the NAT traversal that is not needed.
InitLLQNATState(m);
-#if APPLE_OSX_mDNSResponder
- UpdateAutoTunnelDomainStatuses(m);
-#endif
}
}
@@ -12097,6 +12015,8 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
#ifdef USE_LIBIDN
// If the TLD includes high-ascii bytes, assume it will need to be converted to Punycode.
// (In the future the root name servers may answer UTF-8 queries directly, but for now they do not.)
+ // This applies to the top label (TLD) only
+ // -- for the second level and down we try UTF-8 first, and then fall back to Punycode only if UTF-8 fails.
if (IsHighASCIILabel(LastLabel(&question->qname)))
{
domainname newname;
@@ -12105,11 +12025,11 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
}
#endif // USE_LIBIDN
- question->TargetQID =
#ifndef UNICAST_DISABLED
- (question->Target.type || Question_uDNS(question)) ? mDNS_NewMessageID(m) :
-#endif // UNICAST_DISABLED
- zeroID;
+ question->TargetQID = Question_uDNS(question) ? mDNS_NewMessageID(m) : zeroID;
+#else
+ question->TargetQID = zeroID;
+#endif
debugf("mDNS_StartQuery_internal: %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
// Note: It important that new questions are appended at the *end* of the list, not prepended at the start
@@ -12135,9 +12055,6 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
InitCommonState(m, question);
InitWABState(question);
InitLLQState(question);
-#ifdef DNS_PUSH_ENABLED
- InitDNSPNState(question);
-#endif // DNS_PUSH_ENABLED
InitDNSSECProxyState(m, question);
// FindDuplicateQuestion should be called last after all the intialization
@@ -12169,10 +12086,11 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
}
else
{
-#if BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
m->NumAllInterfaceQuestions++;
- LogInfo("mDNS_StartQuery_internal: NumAllInterfaceRecords %d NumAllInterfaceQuestions %d %##s (%s)",
- m->NumAllInterfaceRecords, m->NumAllInterfaceQuestions, question->qname.c, DNSTypeName(question->qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "mDNS_StartQuery_internal: NumAllInterfaceRecords %u NumAllInterfaceQuestions %u " PRI_DM_NAME " (" PUB_S ")",
+ m->NumAllInterfaceRecords, m->NumAllInterfaceQuestions, DM_NAME_PARAM(&question->qname), DNSTypeName(question->qtype));
if (m->NumAllInterfaceRecords + m->NumAllInterfaceQuestions == 1)
{
m->NextBonjourDisableTime = 0;
@@ -12184,7 +12102,7 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
m->NetworkChanged = m->timenow;
}
}
-#endif // BONJOUR_ON_DEMAND
+#endif
if (question->WakeOnResolve)
{
LogInfo("mDNS_StartQuery_internal: Purging for %##s", question->qname.c);
@@ -12215,7 +12133,7 @@ mDNSexport void CancelGetZoneData(mDNS *const m, ZoneData *nta)
mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const question)
{
CacheGroup *cg = CacheGroupForName(m, question->qnamehash, &question->qname);
- CacheRecord *rr;
+ CacheRecord *cr;
DNSQuestion **qp = &m->Questions;
//LogInfo("mDNS_StopQuery_internal %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
@@ -12233,28 +12151,44 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
return(mStatus_BadReferenceErr);
}
-#if BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
if (!LocalOnlyOrP2PInterface(question->InterfaceID) && mDNSOpaque16IsZero(question->TargetQID))
{
if (m->NumAllInterfaceRecords + m->NumAllInterfaceQuestions == 1)
m->NextBonjourDisableTime = NonZeroTime(m->timenow + (BONJOUR_DISABLE_DELAY * mDNSPlatformOneSecond));
m->NumAllInterfaceQuestions--;
- LogInfo("mDNS_StopQuery_internal: NumAllInterfaceRecords %d NumAllInterfaceQuestions %d %##s (%s)",
- m->NumAllInterfaceRecords, m->NumAllInterfaceQuestions, question->qname.c, DNSTypeName(question->qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "mDNS_StopQuery_internal: NumAllInterfaceRecords %u NumAllInterfaceQuestions %u " PRI_DM_NAME " (" PUB_S ")",
+ m->NumAllInterfaceRecords, m->NumAllInterfaceQuestions, DM_NAME_PARAM(&question->qname), DNSTypeName(question->qtype));
}
-#endif // BONJOUR_ON_DEMAND
+#endif
-#if AWD_METRICS
- if (Question_uDNS(question) && !question->metrics.answered && (question->metrics.querySendCount > 0))
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
+ if (Question_uDNS(question) && !question->metrics.answered && (question->metrics.firstQueryTime != 0))
{
- const domainname * queryName;
- mDNSBool isForCell;
- mDNSu32 durationMs;
+ mDNSu32 querySendCount = question->metrics.querySendCount;
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ if (question->querier)
+ {
+ querySendCount += mdns_querier_get_send_count(question->querier);
+ }
+#endif
+ if (querySendCount > 0)
+ {
+ const domainname * queryName;
+ mDNSBool isForCell;
+ mDNSu32 durationMs;
- queryName = question->metrics.originalQName ? question->metrics.originalQName : &question->qname;
- isForCell = (question->qDNSServer && question->qDNSServer->cellIntf);
- durationMs = ((m->timenow - question->metrics.firstQueryTime) * 1000) / mDNSPlatformOneSecond;
- MetricsUpdateDNSQueryStats(queryName, question->qtype, mDNSNULL, question->metrics.querySendCount, question->metrics.expiredAnswerState, durationMs, isForCell);
+ queryName = question->metrics.originalQName ? question->metrics.originalQName : &question->qname;
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ isForCell = (question->dnsservice && mdns_dns_service_interface_is_cellular(question->dnsservice));
+#else
+ isForCell = (question->qDNSServer && question->qDNSServer->isCell);
+#endif
+ durationMs = ((m->timenow - question->metrics.firstQueryTime) * 1000) / mDNSPlatformOneSecond;
+ MetricsUpdateDNSQueryStats(queryName, question->qtype, mDNSNULL, querySendCount,
+ question->metrics.expiredAnswerState, question->metrics.dnsOverTCPState, durationMs, isForCell);
+ }
}
#endif
// Take care to cut question from list *before* calling UpdateQuestionDuplicates
@@ -12264,9 +12198,9 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
// If there are any cache records referencing this as their active question, then see if there is any
// other question that is also referencing them, else their CRActiveQuestion needs to get set to NULL.
- for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
+ for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
{
- if (rr->CRActiveQuestion == question)
+ if (cr->CRActiveQuestion == question)
{
DNSQuestion *q;
DNSQuestion *replacement = mDNSNULL;
@@ -12276,7 +12210,7 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
// via CacheRecordRmv() when the cache record expires.
for (q = m->Questions; q && (q != m->NewQuestions); q = q->next)
{
- if (!q->DuplicateOf && !QuerySuppressed(q) && ResourceRecordAnswersQuestion(&rr->resrec, q))
+ if (!q->DuplicateOf && !q->Suppressed && CacheRecordAnswersQuestion(cr, q))
{
if (q->ThisQInterval > 0)
{
@@ -12291,8 +12225,8 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
}
if (replacement)
debugf("mDNS_StopQuery_internal: Updating CRActiveQuestion to %p for cache record %s, Original question CurrentAnswers %d, new question "
- "CurrentAnswers %d, SuppressQuery %d", replacement, CRDisplayString(m,rr), question->CurrentAnswers, replacement->CurrentAnswers, replacement->SuppressQuery);
- rr->CRActiveQuestion = replacement; // Question used to be active; new value may or may not be null
+ "CurrentAnswers %d, Suppressed %d", replacement, CRDisplayString(m,cr), question->CurrentAnswers, replacement->CurrentAnswers, replacement->Suppressed);
+ cr->CRActiveQuestion = replacement; // Question used to be active; new value may or may not be null
if (!replacement) m->rrcache_active--; // If no longer active, decrement rrcache_active count
}
}
@@ -12322,13 +12256,6 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
m->RestartQuestion = question->next;
}
- if (m->ValidationQuestion == question)
- {
- LogInfo("mDNS_StopQuery_internal: Just deleted the current Validation question: %##s (%s)",
- question->qname.c, DNSTypeName(question->qtype));
- m->ValidationQuestion = question->next;
- }
-
// Take care not to trash question->next until *after* we've updated m->CurrentQuestion and m->NewQuestions
question->next = mDNSNULL;
@@ -12341,6 +12268,9 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
// *first*, then they're all ready to be updated a second time if necessary when we cancel our GetZoneData query.
if (question->tcp) { DisposeTCPConn(question->tcp); question->tcp = mDNSNULL; }
if (question->LocalSocket) { mDNSPlatformUDPClose(question->LocalSocket); question->LocalSocket = mDNSNULL; }
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ Querier_HandleStoppedDNSQuestion(question);
+#endif
if (!mDNSOpaque16IsZero(question->TargetQID) && question->LongLived)
{
// Scan our list to see if any more wide-area LLQs remain. If not, stop our NAT Traversal.
@@ -12376,44 +12306,21 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
question->tcp = mDNSNULL;
}
}
-#ifdef DNS_PUSH_ENABLED
- else if (question->dnsPushState == DNSPUSH_ESTABLISHED)
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
+ else if (question->dnsPushServer != mDNSNULL)
{
- if (question->tcp)
- {
- UnSubscribeToDNSPushNotificationServer(m, q);
- question->tcp->question = mDNSNULL;
- question->tcp = mDNSNULL;
- }
+ UnSubscribeToDNSPushNotificationServer(m, question);
}
-#endif // DNS_PUSH_ENABLED
-#if APPLE_OSX_mDNSResponder
- UpdateAutoTunnelDomainStatuses(m);
#endif
}
// wait until we send the refresh above which needs the nta
if (question->nta) { CancelGetZoneData(m, question->nta); question->nta = mDNSNULL; }
- if (question->ValidationRequired && question->DNSSECAuthInfo)
- {
- LogInfo("mDNS_StopQuery_internal: freeing DNSSECAuthInfo %##s", question->qname.c);
- question->DAIFreeCallback(m, question->DNSSECAuthInfo);
- question->DNSSECAuthInfo = mDNSNULL;
- }
- if (question->AnonInfo)
- {
- FreeAnonInfo(question->AnonInfo);
- question->AnonInfo = mDNSNULL;
- }
-#if AWD_METRICS
- if (question->metrics.originalQName)
- {
- mDNSPlatformMemFree(question->metrics.originalQName);
- question->metrics.originalQName = mDNSNULL;
- }
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
+ uDNSMetricsClear(&question->metrics);
#endif
-#if USE_DNS64
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
DNS64ResetState(question);
#endif
@@ -12454,16 +12361,18 @@ mDNSexport mStatus mDNS_StopQueryWithRemoves(mDNS *const m, DNSQuestion *const q
status = mDNS_StopQuery_internal(m, question);
if (status == mStatus_NoError && !qq)
{
- const CacheRecord *rr;
+ const CacheRecord *cr;
CacheGroup *const cg = CacheGroupForName(m, question->qnamehash, &question->qname);
LogInfo("Generating terminal removes for %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
- for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
- if (rr->resrec.RecordType != kDNSRecordTypePacketNegative && SameNameRecordAnswersQuestion(&rr->resrec, question))
+ for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
+ {
+ if (cr->resrec.RecordType != kDNSRecordTypePacketNegative && SameNameCacheRecordAnswersQuestion(cr, question))
{
// Don't use mDNS_DropLockBeforeCallback() here, since we don't allow API calls
if (question->QuestionCallback)
- question->QuestionCallback(m, question, &rr->resrec, QC_rmv);
+ question->QuestionCallback(m, question, &cr->resrec, QC_rmv);
}
+ }
}
mDNS_Unlock(m);
return(status);
@@ -12494,13 +12403,12 @@ mDNSexport mStatus mDNS_ReconfirmByValue(mDNS *const m, ResourceRecord *const rr
mDNSlocal mStatus mDNS_StartBrowse_internal(mDNS *const m, DNSQuestion *const question,
const domainname *const srv, const domainname *const domain,
- const mDNSu8 *anondata, const mDNSInterfaceID InterfaceID, mDNSu32 flags,
+ const mDNSInterfaceID InterfaceID, mDNSu32 flags,
mDNSBool ForceMCast, mDNSBool useBackgroundTrafficClass,
mDNSQuestionCallback *Callback, void *Context)
{
question->InterfaceID = InterfaceID;
question->flags = flags;
- question->Target = zeroAddr;
question->qtype = kDNSType_PTR;
question->qclass = kDNSClass_IN;
question->LongLived = mDNStrue;
@@ -12508,42 +12416,29 @@ mDNSlocal mStatus mDNS_StartBrowse_internal(mDNS *const m, DNSQuestion *const qu
question->ForceMCast = ForceMCast;
question->ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
question->SuppressUnusable = mDNSfalse;
- question->SearchListIndex = 0;
- question->AppendSearchDomains = 0;
- question->RetryWithSearchDomains = mDNSfalse;
+ question->AppendSearchDomains = mDNSfalse;
question->TimeoutQuestion = 0;
question->WakeOnResolve = 0;
- question->UseBackgroundTrafficClass = useBackgroundTrafficClass;
- question->ValidationRequired = 0;
- question->ValidatingResponse = 0;
+ question->UseBackgroundTraffic = useBackgroundTrafficClass;
question->ProxyQuestion = 0;
- question->qnameOrig = mDNSNULL;
- question->AnonInfo = mDNSNULL;
question->QuestionCallback = Callback;
question->QuestionContext = Context;
if (!ConstructServiceName(&question->qname, mDNSNULL, srv, domain))
return(mStatus_BadParamErr);
- if (anondata)
- {
- question->AnonInfo = AllocateAnonInfo(&question->qname, anondata, mDNSPlatformStrLen(anondata), mDNSNULL);
- if (!question->AnonInfo)
- return(mStatus_BadParamErr);
- }
-
return(mDNS_StartQuery_internal(m, question));
}
mDNSexport mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question,
const domainname *const srv, const domainname *const domain,
- const mDNSu8 *anondata, const mDNSInterfaceID InterfaceID, mDNSu32 flags,
+ const mDNSInterfaceID InterfaceID, mDNSu32 flags,
mDNSBool ForceMCast, mDNSBool useBackgroundTrafficClass,
mDNSQuestionCallback *Callback, void *Context)
{
mStatus status;
mDNS_Lock(m);
- status = mDNS_StartBrowse_internal(m, question, srv, domain, anondata, InterfaceID, flags, ForceMCast, useBackgroundTrafficClass, Callback, Context);
+ status = mDNS_StartBrowse_internal(m, question, srv, domain, InterfaceID, flags, ForceMCast, useBackgroundTrafficClass, Callback, Context);
mDNS_Unlock(m);
return(status);
}
@@ -12554,7 +12449,6 @@ mDNSexport mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, m
{
question->InterfaceID = InterfaceID;
question->flags = 0;
- question->Target = zeroAddr;
question->qtype = kDNSType_PTR;
question->qclass = kDNSClass_IN;
question->LongLived = mDNSfalse;
@@ -12562,17 +12456,11 @@ mDNSexport mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, m
question->ForceMCast = mDNSfalse;
question->ReturnIntermed = mDNSfalse;
question->SuppressUnusable = mDNSfalse;
- question->SearchListIndex = 0;
- question->AppendSearchDomains = 0;
- question->RetryWithSearchDomains = mDNSfalse;
+ question->AppendSearchDomains = mDNSfalse;
question->TimeoutQuestion = 0;
question->WakeOnResolve = 0;
- question->UseBackgroundTrafficClass = mDNSfalse;
- question->ValidationRequired = 0;
- question->ValidatingResponse = 0;
+ question->UseBackgroundTraffic = mDNSfalse;
question->ProxyQuestion = 0;
- question->qnameOrig = mDNSNULL;
- question->AnonInfo = mDNSNULL;
question->pid = mDNSPlatformGetPID();
question->euid = 0;
question->QuestionCallback = Callback;
@@ -12678,58 +12566,105 @@ mDNSexport mStatus mDNS_Deregister(mDNS *const m, AuthRecord *const rr)
// Circular reference: AdvertiseInterface references mDNS_HostNameCallback, which calls mDNS_SetFQDN, which call AdvertiseInterface
mDNSlocal void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+mDNSlocal void mDNS_RandomizedHostNameCallback(mDNS *m, AuthRecord *rr, mStatus result);
+#endif
+
+mDNSlocal AuthRecord *GetInterfaceAddressRecord(NetworkInterfaceInfo *intf, mDNSBool forRandHostname)
+{
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ return(forRandHostname ? &intf->RR_AddrRand : &intf->RR_A);
+#else
+ (void)forRandHostname; // Unused.
+ return(&intf->RR_A);
+#endif
+}
-mDNSlocal NetworkInterfaceInfo *FindFirstAdvertisedInterface(mDNS *const m)
+mDNSlocal AuthRecord *GetFirstAddressRecordEx(const mDNS *const m, const mDNSBool forRandHostname)
{
NetworkInterfaceInfo *intf;
for (intf = m->HostInterfaces; intf; intf = intf->next)
- if (intf->Advertise) break;
- return(intf);
+ {
+ if (!intf->Advertise) continue;
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ if (mDNSPlatformInterfaceIsAWDL(intf->InterfaceID)) continue;
+#endif
+ return(GetInterfaceAddressRecord(intf, forRandHostname));
+ }
+ return(mDNSNULL);
}
+#define GetFirstAddressRecord(M) GetFirstAddressRecordEx(M, mDNSfalse)
// The parameter "set" here refers to the set of AuthRecords used to advertise this interface.
// (It's a set of records, not a set of interfaces.)
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool useRandomizedHostname)
+#else
mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
+#endif
{
+ const domainname *hostname;
+ mDNSRecordCallback *hostnameCallback;
+ AuthRecord *addrAR;
+ AuthRecord *ptrAR;
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ const mDNSBool interfaceIsAWDL = mDNSPlatformInterfaceIsAWDL(set->InterfaceID);
+#endif
+ mDNSu8 addrRecordType;
char buffer[MAX_REVERSE_MAPPING_NAME];
- NetworkInterfaceInfo *primary;
- mDNSu8 recordType;
- if (m->AutoTargetServices == 0)
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ if (interfaceIsAWDL || useRandomizedHostname)
{
- LogInfo("AdvertiseInterface: Returning due to AutoTargetServices zero for %s", set->ifname);
- return;
+ hostname = &m->RandomizedHostname;
+ hostnameCallback = mDNS_RandomizedHostNameCallback;
+ }
+ else
+#endif
+ {
+ hostname = &m->MulticastHostname;
+ hostnameCallback = mDNS_HostNameCallback;
}
- primary = FindFirstAdvertisedInterface(m);
- if (!primary) primary = set; // If no existing advertised interface, this new NetworkInterfaceInfo becomes our new primary
- // We should never have primary be NULL, because even if there is
- // no other interface yet, we should always find ourself in the list.
-
- // If interface is marked as a direct link, we can assume the address record is unique
- // and does not need to go through the probe phase of the probe/announce packet sequence.
- recordType = (set->DirectLink ? kDNSRecordTypeKnownUnique : kDNSRecordTypeUnique);
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ if (!interfaceIsAWDL && useRandomizedHostname)
+ {
+ addrAR = &set->RR_AddrRand;
+ ptrAR = mDNSNULL;
+ }
+ else
+#endif
+ {
+ addrAR = &set->RR_A;
+ ptrAR = &set->RR_PTR;
+ }
+ if (addrAR->resrec.RecordType != kDNSRecordTypeUnregistered) return;
- if (set->DirectLink)
- LogInfo("AdvertiseInterface: Marking address record as kDNSRecordTypeKnownUnique for %s", set->ifname);
+ addrRecordType = set->DirectLink ? kDNSRecordTypeKnownUnique : kDNSRecordTypeUnique;
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ if (hostname == &m->RandomizedHostname) addrRecordType = kDNSRecordTypeKnownUnique;
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+ "AdvertiseInterface: Advertising " PUB_S " hostname on interface " PUB_S,
+ (hostname == &m->RandomizedHostname) ? "randomized" : "normal", set->ifname);
+#else
+ LogInfo("AdvertiseInterface: Advertising for ifname %s", set->ifname);
+#endif
// Send dynamic update for non-linklocal IPv4 Addresses
- mDNS_SetupResourceRecord(&set->RR_A, mDNSNULL, set->InterfaceID, kDNSType_A, kHostNameTTL, recordType, AuthRecordAny, mDNS_HostNameCallback, set);
- mDNS_SetupResourceRecord(&set->RR_PTR, mDNSNULL, set->InterfaceID, kDNSType_PTR, kHostNameTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
- mDNS_SetupResourceRecord(&set->RR_HINFO, mDNSNULL, set->InterfaceID, kDNSType_HINFO, kHostNameTTL, kDNSRecordTypeUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
+ mDNS_SetupResourceRecord(addrAR, mDNSNULL, set->InterfaceID, kDNSType_A, kHostNameTTL, addrRecordType, AuthRecordAny, hostnameCallback, set);
+ if (ptrAR) mDNS_SetupResourceRecord(ptrAR, mDNSNULL, set->InterfaceID, kDNSType_PTR, kHostNameTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
#if ANSWER_REMOTE_HOSTNAME_QUERIES
- set->RR_A.AllowRemoteQuery = mDNStrue;
- set->RR_PTR.AllowRemoteQuery = mDNStrue;
- set->RR_HINFO.AllowRemoteQuery = mDNStrue;
+ addrAR->AllowRemoteQuery = mDNStrue;
+ if (ptrAR) ptrAR->AllowRemoteQuery = mDNStrue;
#endif
// 1. Set up Address record to map from host name ("foo.local.") to IP address
// 2. Set up reverse-lookup PTR record to map from our address back to our host name
- AssignDomainName(&set->RR_A.namestorage, &m->MulticastHostname);
+ AssignDomainName(&addrAR->namestorage, hostname);
if (set->ip.type == mDNSAddrType_IPv4)
{
- set->RR_A.resrec.rrtype = kDNSType_A;
- set->RR_A.resrec.rdata->u.ipv4 = set->ip.ip.v4;
+ addrAR->resrec.rrtype = kDNSType_A;
+ addrAR->resrec.rdata->u.ipv4 = set->ip.ip.v4;
// Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.",
set->ip.ip.v4.b[3], set->ip.ip.v4.b[2], set->ip.ip.v4.b[1], set->ip.ip.v4.b[0]);
@@ -12737,8 +12672,8 @@ mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
else if (set->ip.type == mDNSAddrType_IPv6)
{
int i;
- set->RR_A.resrec.rrtype = kDNSType_AAAA;
- set->RR_A.resrec.rdata->u.ipv6 = set->ip.ip.v6;
+ addrAR->resrec.rrtype = kDNSType_AAAA;
+ addrAR->resrec.rdata->u.ipv6 = set->ip.ip.v6;
for (i = 0; i < 16; i++)
{
static const char hexValues[] = "0123456789ABCDEF";
@@ -12750,102 +12685,114 @@ mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
mDNS_snprintf(&buffer[64], sizeof(buffer)-64, "ip6.arpa.");
}
- MakeDomainNameFromDNSNameString(&set->RR_PTR.namestorage, buffer);
- set->RR_PTR.AutoTarget = Target_AutoHost; // Tell mDNS that the target of this PTR is to be kept in sync with our host name
- set->RR_PTR.ForceMCast = mDNStrue; // This PTR points to our dot-local name, so don't ever try to write it into a uDNS server
-
- set->RR_A.RRSet = &primary->RR_A; // May refer to self
+ if (ptrAR)
+ {
+ MakeDomainNameFromDNSNameString(&ptrAR->namestorage, buffer);
+ ptrAR->AutoTarget = Target_AutoHost; // Tell mDNS that the target of this PTR is to be kept in sync with our host name
+ ptrAR->ForceMCast = mDNStrue; // This PTR points to our dot-local name, so don't ever try to write it into a uDNS server
+ }
- mDNS_Register_internal(m, &set->RR_A);
- mDNS_Register_internal(m, &set->RR_PTR);
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ addrAR->RRSet = interfaceIsAWDL ? addrAR : GetFirstAddressRecordEx(m, useRandomizedHostname);
+#else
+ addrAR->RRSet = GetFirstAddressRecord(m);
+#endif
+ if (!addrAR->RRSet) addrAR->RRSet = addrAR;
+ mDNS_Register_internal(m, addrAR);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG, "Initialized RRSet for " PRI_S, ARDisplayString(m, addrAR));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG, "RRSet: " PRI_S, ARDisplayString(m, addrAR->RRSet));
+ if (ptrAR) mDNS_Register_internal(m, ptrAR);
-#if APPLE_OSX_mDNSResponder
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
// must be after the mDNS_Register_internal() calls so that records have complete rdata fields, etc
D2D_start_advertising_interface(set);
-#endif // APPLE_OSX_mDNSResponder
+#endif
+}
- if (!NO_HINFO && m->HIHardware.c[0] > 0 && m->HISoftware.c[0] > 0 && m->HIHardware.c[0] + m->HISoftware.c[0] <= 254)
+mDNSlocal void AdvertiseInterfaceIfNeeded(mDNS *const m, NetworkInterfaceInfo *set)
+{
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ if (mDNSPlatformInterfaceIsAWDL(set->InterfaceID))
{
- mDNSu8 *p = set->RR_HINFO.resrec.rdata->u.data;
- AssignDomainName(&set->RR_HINFO.namestorage, &m->MulticastHostname);
- set->RR_HINFO.DependentOn = &set->RR_A;
- mDNSPlatformMemCopy(p, &m->HIHardware, 1 + (mDNSu32)m->HIHardware.c[0]);
- p += 1 + (int)p[0];
- mDNSPlatformMemCopy(p, &m->HISoftware, 1 + (mDNSu32)m->HISoftware.c[0]);
- mDNS_Register_internal(m, &set->RR_HINFO);
+ if ((m->AutoTargetAWDLIncludedCount > 0) || (m->AutoTargetAWDLOnlyCount > 0))
+ {
+ AdvertiseInterface(m, set, mDNSfalse);
+ }
}
else
{
- debugf("Not creating HINFO record: platform support layer provided no information");
- set->RR_HINFO.resrec.RecordType = kDNSRecordTypeUnregistered;
+ if (m->AutoTargetServices > 0) AdvertiseInterface(m, set, mDNSfalse);
+ if (m->AutoTargetAWDLIncludedCount > 0) AdvertiseInterface(m, set, mDNStrue);
}
+#else
+ if (m->AutoTargetServices > 0) AdvertiseInterface(m, set);
+#endif
}
-mDNSlocal void DeadvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
+mDNSlocal void DeadvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set, DeadvertiseFlags flags)
{
- if (m->AutoTargetServices == 0)
- {
- LogInfo("DeadvertiseInterface: Returning due to AutoTargetServices zero for %s", set->ifname);
- return;
- }
-
-#if APPLE_OSX_mDNSResponder
- D2D_stop_advertising_interface(set);
-#endif // APPLE_OSX_mDNSResponder
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ const mDNSBool interfaceIsAWDL = mDNSPlatformInterfaceIsAWDL(set->InterfaceID);
+#endif
// Unregister these records.
// When doing the mDNS_Exit processing, we first call DeadvertiseInterface for each interface, so by the time the platform
// support layer gets to call mDNS_DeregisterInterface, the address and PTR records have already been deregistered for it.
// Also, in the event of a name conflict, one or more of our records will have been forcibly deregistered.
// To avoid unnecessary and misleading warning messages, we check the RecordType before calling mDNS_Deregister_internal().
- if (set->RR_A .resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_A, mDNS_Dereg_normal);
- if (set->RR_PTR .resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_PTR, mDNS_Dereg_normal);
- if (set->RR_HINFO.resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_HINFO, mDNS_Dereg_normal);
-}
-
-mDNSlocal void AdvertiseAllInterfaceRecords(mDNS *const m)
-{
- NetworkInterfaceInfo *intf;
- for (intf = m->HostInterfaces; intf; intf = intf->next)
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ if ((!interfaceIsAWDL && (flags & kDeadvertiseFlag_NormalHostname)) ||
+ ( interfaceIsAWDL && (flags & kDeadvertiseFlag_RandHostname)))
+#else
+ if (flags & kDeadvertiseFlag_NormalHostname)
+#endif
{
- if (intf->Advertise)
- {
- LogInfo("AdvertiseInterface: Advertising for ifname %s", intf->ifname);
- AdvertiseInterface(m, intf);
- }
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+ "DeadvertiseInterface: Deadvertising " PUB_S " hostname on interface " PUB_S,
+ (flags & kDeadvertiseFlag_RandHostname) ? "randomized" : "normal", set->ifname);
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+ D2D_stop_advertising_interface(set);
+#endif
+ if (set->RR_A.resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_A, mDNS_Dereg_normal);
+ if (set->RR_PTR.resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_PTR, mDNS_Dereg_normal);
}
-}
-
-mDNSlocal void DeadvertiseAllInterfaceRecords(mDNS *const m)
-{
- NetworkInterfaceInfo *intf;
- for (intf = m->HostInterfaces; intf; intf = intf->next)
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ if (!interfaceIsAWDL && (flags & kDeadvertiseFlag_RandHostname))
{
- if (intf->Advertise)
- {
- LogInfo("DeadvertiseInterface: Deadvertising for ifname %s", intf->ifname);
- DeadvertiseInterface(m, intf);
- }
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+ "DeadvertiseInterface: Deadvertising randomized hostname on interface " PUB_S, set->ifname);
+ AuthRecord *const ar = &set->RR_AddrRand;
+ if (ar->resrec.RecordType) mDNS_Deregister_internal(m, ar, mDNS_Dereg_normal);
}
+#endif
}
// Change target host name for record.
mDNSlocal void UpdateTargetHostName(mDNS *const m, AuthRecord *const rr)
{
-#if APPLE_OSX_mDNSResponder
- // If this record was also registered with any D2D plugins, stop advertising
- // the version with the old host name.
- D2D_stop_advertising_record(rr);
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+ // If this record was also registered with any D2D plugins, stop advertising
+ // the version with the old host name.
+ D2D_stop_advertising_record(rr);
#endif
SetTargetToHostName(m, rr);
-#if APPLE_OSX_mDNSResponder
- // Advertise the record with the updated host name with the D2D plugins if appropriate.
- D2D_start_advertising_record(rr);
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+ // Advertise the record with the updated host name with the D2D plugins if appropriate.
+ D2D_start_advertising_record(rr);
#endif
}
+mDNSlocal void DeadvertiseAllInterfaceRecords(mDNS *const m, DeadvertiseFlags flags)
+{
+ NetworkInterfaceInfo *intf;
+ for (intf = m->HostInterfaces; intf; intf = intf->next)
+ {
+ if (intf->Advertise) DeadvertiseInterface(m, intf, flags);
+ }
+}
+
mDNSexport void mDNS_SetFQDN(mDNS *const m)
{
domainname newmname;
@@ -12861,8 +12808,8 @@ mDNSexport void mDNS_SetFQDN(mDNS *const m)
else
{
AssignDomainName(&m->MulticastHostname, &newmname);
- DeadvertiseAllInterfaceRecords(m);
- AdvertiseAllInterfaceRecords(m);
+ DeadvertiseAllInterfaceRecords(m, kDeadvertiseFlag_NormalHostname);
+ AdvertiseNecessaryInterfaceRecords(m);
}
// 3. Make sure that any AutoTarget SRV records (and the like) get updated
@@ -12920,6 +12867,44 @@ mDNSlocal void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatu
LogMsg("mDNS_HostNameCallback: Unknown error %d for registration of record %s", result, rr->resrec.name->c);
}
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+mDNSlocal void mDNS_RandomizedHostNameCallback(mDNS *const m, AuthRecord *const addrRecord, const mStatus result)
+{
+ (void)addrRecord; // Unused parameter
+
+ if (result == mStatus_NameConflict)
+ {
+ AuthRecord *rr;
+ domainlabel newUUIDLabel;
+
+ GetRandomUUIDLabel(&newUUIDLabel);
+ if (SameDomainLabel(newUUIDLabel.c, m->RandomizedHostname.c))
+ {
+ IncrementLabelSuffix(&newUUIDLabel, mDNSfalse);
+ }
+
+ mDNS_Lock(m);
+
+ m->RandomizedHostname.c[0] = 0;
+ AppendDomainLabel(&m->RandomizedHostname, &newUUIDLabel);
+ AppendLiteralLabelString(&m->RandomizedHostname, "local");
+
+ DeadvertiseAllInterfaceRecords(m, kDeadvertiseFlag_RandHostname);
+ AdvertiseNecessaryInterfaceRecords(m);
+ for (rr = m->ResourceRecords; rr; rr = rr->next)
+ {
+ if (rr->AutoTarget && AuthRecordIncludesOrIsAWDL(rr)) UpdateTargetHostName(m, rr);
+ }
+ for (rr = m->DuplicateRecords; rr; rr = rr->next)
+ {
+ if (rr->AutoTarget && AuthRecordIncludesOrIsAWDL(rr)) UpdateTargetHostName(m, rr);
+ }
+
+ mDNS_Unlock(m);
+ }
+}
+#endif
+
mDNSlocal void UpdateInterfaceProtocols(mDNS *const m, NetworkInterfaceInfo *active)
{
NetworkInterfaceInfo *intf;
@@ -12976,7 +12961,7 @@ mDNSexport void mDNS_ActivateNetWake_internal(mDNS *const m, NetworkInterfaceInf
if (set->InterfaceActive)
{
LogSPS("ActivateNetWake for %s (%#a)", set->ifname, &set->ip);
- mDNS_StartBrowse_internal(m, &set->NetWakeBrowse, &SleepProxyServiceType, &localdomain, mDNSNULL, set->InterfaceID, 0, mDNSfalse, mDNSfalse, m->SPSBrowseCallback, set);
+ mDNS_StartBrowse_internal(m, &set->NetWakeBrowse, &SleepProxyServiceType, &localdomain, set->InterfaceID, 0, mDNSfalse, mDNSfalse, m->SPSBrowseCallback, set);
}
}
@@ -13020,10 +13005,19 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
NetworkInterfaceInfo **p = &m->HostInterfaces;
if (!set->InterfaceID)
- { LogMsg("mDNS_RegisterInterface: Error! Tried to register a NetworkInterfaceInfo %#a with zero InterfaceID", &set->ip); return(mStatus_Invalid); }
+ {
+ LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_ERROR,
+ "Tried to register a NetworkInterfaceInfo with zero InterfaceID - ifaddr: " PRI_IP_ADDR, &set->ip);
+ return(mStatus_Invalid);
+ }
if (!mDNSAddressIsValidNonZero(&set->mask))
- { LogMsg("mDNS_RegisterInterface: Error! Tried to register a NetworkInterfaceInfo %#a with invalid mask %#a", &set->ip, &set->mask); return(mStatus_Invalid); }
+ {
+ LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_ERROR,
+ "Tried to register a NetworkInterfaceInfo with invalid mask - ifaddr: " PRI_IP_ADDR ", ifmask: " PUB_IP_ADDR,
+ &set->ip, &set->mask);
+ return(mStatus_Invalid);
+ }
mDNS_Lock(m);
@@ -13039,7 +13033,9 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
{
if (*p == set)
{
- LogMsg("mDNS_RegisterInterface: Error! Tried to register a NetworkInterfaceInfo that's already in the list");
+ LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_ERROR,
+ "Tried to register a NetworkInterfaceInfo that's already in the list - "
+ "ifname: " PUB_S ", ifaddr: " PRI_IP_ADDR, set->ifname, &set->ip);
mDNS_Unlock(m);
return(mStatus_AlreadyRegistered);
}
@@ -13059,14 +13055,20 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
set->next = mDNSNULL;
*p = set;
- if (set->Advertise)
- AdvertiseInterface(m, set);
+ if (set->Advertise) AdvertiseInterfaceIfNeeded(m, set);
- LogInfo("mDNS_RegisterInterface: InterfaceID %d %s (%#a) %s",
- (uint32_t)set->InterfaceID, set->ifname, &set->ip,
- set->InterfaceActive ?
- "not represented in list; marking active and retriggering queries" :
- "already represented in list; marking inactive for now");
+ if (set->InterfaceActive)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_INFO,
+ "Interface not represented in list; marking active and retriggering queries - "
+ "ifid: %d, ifname: " PUB_S ", ifaddr: " PRI_IP_ADDR, IIDPrintable(set->InterfaceID), set->ifname, &set->ip);
+ }
+ else
+ {
+ LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_INFO,
+ "Interface already represented in list - "
+ "ifid: %d, ifname: " PUB_S ", ifaddr: " PRI_IP_ADDR, IIDPrintable(set->InterfaceID), set->ifname, &set->ip);
+ }
if (set->NetWake) mDNS_ActivateNetWake_internal(m, set);
@@ -13091,15 +13093,21 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
case FastActivation:
probedelay = (mDNSs32)0;
numannounce = InitialAnnounceCount;
- LogMsg("mDNS_RegisterInterface: Using fast activation for DirectLink interface %s (%#a)", set->ifname, &set->ip);
+ LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
+ "Using fast activation for DirectLink interface - ifname: " PUB_S ", ifaddr: " PRI_IP_ADDR,
+ set->ifname, &set->ip);
break;
+#if MDNSRESPONDER_SUPPORTS(APPLE, SLOW_ACTIVATION)
case SlowActivation:
probedelay = mDNSPlatformOneSecond * 5;
numannounce = (mDNSu8)1;
- LogMsg("mDNS_RegisterInterface: Frequent transitions for interface %s (%#a), doing slow activation", set->ifname, &set->ip);
+ LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
+ "Frequent transitions for interface, doing slow activation - "
+ "ifname: " PUB_S ", ifaddr: " PRI_IP_ADDR, set->ifname, &set->ip);
m->mDNSStats.InterfaceUpFlap++;
break;
+#endif
case NormalActivation:
default:
@@ -13108,7 +13116,9 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
break;
}
- LogInfo("mDNS_RegisterInterface: %s (%#a) probedelay %d", set->ifname, &set->ip, probedelay);
+ LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_INFO,
+ "Interface probe will be delayed - ifname: " PUB_S ", ifaddr: " PRI_IP_ADDR ", probe delay: %d",
+ set->ifname, &set->ip, probedelay);
// No probe or sending suppression on DirectLink type interfaces.
if (activationSpeed == FastActivation)
@@ -13140,7 +13150,7 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
// us to reconnect to the network. If we do this as part of the wake up code, it is possible
// that the network link comes UP after 60 seconds and we never set the OWNER option
m->AnnounceOwner = NonZeroTime(m->timenow + 60 * mDNSPlatformOneSecond);
- LogInfo("mDNS_RegisterInterface: Setting AnnounceOwner");
+ LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEBUG, "Setting AnnounceOwner");
m->mDNSStats.InterfaceUp++;
for (q = m->Questions; q; q=q->next) // Scan our list of questions
@@ -13149,11 +13159,21 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
{
if (!q->InterfaceID || q->InterfaceID == set->InterfaceID) // If non-specific Q, or Q on this specific interface,
{ // then reactivate this question
+#if MDNSRESPONDER_SUPPORTS(APPLE, SLOW_ACTIVATION)
// If flapping, delay between first and second queries is nine seconds instead of one second
mDNSBool dodelay = (activationSpeed == SlowActivation) && (q->FlappingInterface1 == set->InterfaceID || q->FlappingInterface2 == set->InterfaceID);
mDNSs32 initial = dodelay ? InitialQuestionInterval * QuestionIntervalStep2 : InitialQuestionInterval;
mDNSs32 qdelay = dodelay ? kDefaultQueryDelayTimeForFlappingInterface : 0;
- if (dodelay) LogInfo("No cache records expired for %##s (%s); delaying questions by %d seconds", q->qname.c, DNSTypeName(q->qtype), qdelay);
+ if (dodelay)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_INFO,
+ "No cache records expired for the question " PRI_DM_NAME " (" PUB_S ");"
+ " delaying it by %d seconds", DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype), qdelay);
+ }
+#else
+ mDNSs32 initial = InitialQuestionInterval;
+ mDNSs32 qdelay = 0;
+#endif
if (!q->ThisQInterval || q->ThisQInterval > initial)
{
@@ -13162,8 +13182,6 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
}
q->LastQTime = m->timenow - q->ThisQInterval + qdelay;
q->RecentAnswerPkts = 0;
- // Change the salt
- ReInitAnonInfo(&q->AnonInfo, &q->qname);
SetNextQueryTime(m,q);
}
}
@@ -13175,14 +13193,9 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
{
if (!rr->resrec.InterfaceID || rr->resrec.InterfaceID == set->InterfaceID)
{
- // Change the salt
- ReInitAnonInfo(&rr->resrec.AnonInfo, rr->resrec.name);
mDNSCoreRestartRegistration(m, rr, numannounce);
}
}
-#if APPLE_OSX_mDNSResponder && !TARGET_OS_IPHONE
- DNSSECProbe(m);
-#endif
}
RestartRecordGetZoneData(m);
@@ -13193,22 +13206,58 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
return(mStatus_NoError);
}
+mDNSlocal void AdjustAddressRecordSetsEx(mDNS *const m, NetworkInterfaceInfo *removedIntf, mDNSBool forRandHostname)
+{
+ NetworkInterfaceInfo *intf;
+ const AuthRecord *oldAR;
+ AuthRecord *newAR;
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ if (mDNSPlatformInterfaceIsAWDL(removedIntf->InterfaceID)) return;
+#endif
+ oldAR = GetInterfaceAddressRecord(removedIntf, forRandHostname);
+ newAR = GetFirstAddressRecordEx(m, forRandHostname);
+ for (intf = m->HostInterfaces; intf; intf = intf->next)
+ {
+ AuthRecord *ar;
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ if (mDNSPlatformInterfaceIsAWDL(intf->InterfaceID)) continue;
+#endif
+ ar = GetInterfaceAddressRecord(intf, forRandHostname);
+ if (ar->RRSet == oldAR)
+ {
+ ar->RRSet = newAR ? newAR : ar;
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG, "Changed RRSet for " PRI_S, ARDisplayString(m, ar));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG, "New RRSet: " PRI_S, ARDisplayString(m, ar->RRSet));
+ }
+ }
+}
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+#define AdjustAddressRecordSetsForRandHostname(M, REMOVED_INTF) AdjustAddressRecordSetsEx(M, REMOVED_INTF, mDNStrue)
+#endif
+#define AdjustAddressRecordSets(M, REMOVED_INTF) AdjustAddressRecordSetsEx(M, REMOVED_INTF, mDNSfalse)
+
// Note: mDNS_DeregisterInterface calls mDNS_Deregister_internal which can call a user callback, which may change
// the record list and/or question list.
// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, InterfaceActivationSpeed activationSpeed)
{
+#if !MDNSRESPONDER_SUPPORTS(APPLE, SLOW_ACTIVATION)
+ (void)activationSpeed; // Unused parameter
+#endif
NetworkInterfaceInfo **p = &m->HostInterfaces;
mDNSBool revalidate = mDNSfalse;
- NetworkInterfaceInfo *primary;
NetworkInterfaceInfo *intf;
- AuthRecord *A;
mDNS_Lock(m);
// Find this record in our list
while (*p && *p != set) p=&(*p)->next;
- if (!*p) { debugf("mDNS_DeregisterInterface: NetworkInterfaceInfo not found in list"); mDNS_Unlock(m); return; }
+ if (!*p)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEBUG, "NetworkInterfaceInfo not found in list");
+ mDNS_Unlock(m);
+ return;
+ }
mDNS_DeactivateNetWake_internal(m, set);
@@ -13228,10 +13277,15 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se
intf = FirstInterfaceForID(m, set->InterfaceID);
if (intf)
{
- LogInfo("mDNS_DeregisterInterface: Another representative of InterfaceID %d %s (%#a) exists;"
- " making it active", (uint32_t)set->InterfaceID, set->ifname, &set->ip);
+ LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_INFO,
+ "Another representative of InterfaceID exists - ifid: %d, ifname: " PUB_S ", ifaddr: " PRI_IP_ADDR,
+ IIDPrintable(set->InterfaceID), set->ifname, &set->ip);
if (intf->InterfaceActive)
- LogMsg("mDNS_DeregisterInterface: ERROR intf->InterfaceActive already set for %s (%#a)", set->ifname, &set->ip);
+ {
+ LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_ERROR,
+ "intf->InterfaceActive already set for interface - ifname: " PUB_S ", ifaddr: " PRI_IP_ADDR,
+ set->ifname, &set->ip);
+ }
intf->InterfaceActive = mDNStrue;
UpdateInterfaceProtocols(m, intf);
@@ -13250,27 +13304,41 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se
CacheGroup *cg;
CacheRecord *rr;
DNSQuestion *q;
-
- LogInfo("mDNS_DeregisterInterface: Last representative of InterfaceID %d %s (%#a) deregistered;"
- " marking questions etc. dormant", (uint32_t)set->InterfaceID, set->ifname, &set->ip);
+#if MDNSRESPONDER_SUPPORTS(APPLE, CACHE_ANALYTICS)
+ mDNSu32 cacheHitMulticastCount = 0;
+ mDNSu32 cacheMissMulticastCount = 0;
+ mDNSu32 cacheHitUnicastCount = 0;
+ mDNSu32 cacheMissUnicastCount = 0;
+#endif
+ LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_INFO,
+ "Last representative of InterfaceID deregistered; marking questions etc. dormant - "
+ "ifid: %d, ifname: " PUB_S ", ifaddr: " PRI_IP_ADDR,
+ IIDPrintable(set->InterfaceID), set->ifname, &set->ip);
m->mDNSStats.InterfaceDown++;
-
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, SLOW_ACTIVATION)
if (set->McastTxRx && (activationSpeed == SlowActivation))
{
- LogMsg("mDNS_DeregisterInterface: Frequent transitions for interface %s (%#a)", set->ifname, &set->ip);
+ LogRedact(MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_DEFAULT,
+ "Frequent transitions for interface - ifname: " PUB_S ", ifaddr: " PRI_IP_ADDR,
+ set->ifname, &set->ip);
m->mDNSStats.InterfaceDownFlap++;
}
+#endif
// 1. Deactivate any questions specific to this interface, and tag appropriate questions
// so that mDNS_RegisterInterface() knows how swiftly it needs to reactivate them
for (q = m->Questions; q; q=q->next)
{
- if (q->InterfaceID == set->InterfaceID) q->ThisQInterval = 0;
- if (!q->InterfaceID || q->InterfaceID == set->InterfaceID)
+ if (mDNSOpaque16IsZero(q->TargetQID)) // Only deactivate multicast quesstions. (Unicast questions are stopped when/if the associated DNS server group goes away.)
{
- q->FlappingInterface2 = q->FlappingInterface1;
- q->FlappingInterface1 = set->InterfaceID; // Keep history of the last two interfaces to go away
+ if (q->InterfaceID == set->InterfaceID) q->ThisQInterval = 0;
+ if (!q->InterfaceID || q->InterfaceID == set->InterfaceID)
+ {
+ q->FlappingInterface2 = q->FlappingInterface1;
+ q->FlappingInterface1 = set->InterfaceID; // Keep history of the last two interfaces to go away
+ }
}
}
@@ -13280,6 +13348,7 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se
{
if (rr->resrec.InterfaceID == set->InterfaceID)
{
+#if MDNSRESPONDER_SUPPORTS(APPLE, SLOW_ACTIVATION)
// If this interface is deemed flapping,
// postpone deleting the cache records in case the interface comes back again
if (set->McastTxRx && (activationSpeed == SlowActivation))
@@ -13292,26 +13361,48 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se
rr->UnansweredQueries = MaxUnansweredQueries;
}
else
+#endif
{
- rr->resrec.mortality = Mortality_Mortal;
+#if MDNSRESPONDER_SUPPORTS(APPLE, CACHE_ANALYTICS)
+ if (rr->LastCachedAnswerTime)
+ {
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ if (rr->resrec.dnsservice) cacheHitUnicastCount++;
+#else
+ if (rr->resrec.rDNSServer) cacheHitUnicastCount++;
+#endif
+ else cacheHitMulticastCount++;
+ }
+ else
+ {
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ if (rr->resrec.dnsservice) cacheMissUnicastCount++;
+#else
+ if (rr->resrec.rDNSServer) cacheMissUnicastCount++;
+#endif
+ else cacheMissMulticastCount++;
+ }
+#endif
mDNS_PurgeCacheResourceRecord(m, rr);
}
}
}
+#if MDNSRESPONDER_SUPPORTS(APPLE, CACHE_ANALYTICS)
+ dnssd_analytics_update_cache_usage_counts(cacheHitMulticastCount, cacheMissMulticastCount, cacheHitUnicastCount, cacheMissUnicastCount);
+#endif
}
}
// If we still have address records referring to this one, update them.
// This is safe, because this NetworkInterfaceInfo has already been unlinked from the list,
- // so the call to FindFirstAdvertisedInterface() won’t accidentally find it.
- primary = FindFirstAdvertisedInterface(m);
- A = primary ? &primary->RR_A : mDNSNULL;
- for (intf = m->HostInterfaces; intf; intf = intf->next)
- if (intf->RR_A.RRSet == &set->RR_A)
- intf->RR_A.RRSet = A;
+ // so the call to AdjustAddressRecordSets*() won’t accidentally find it.
+ AdjustAddressRecordSets(m, set);
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ AdjustAddressRecordSetsForRandHostname(m, set);
+#endif
// If we were advertising on this interface, deregister those address and reverse-lookup records now
- if (set->Advertise) DeadvertiseInterface(m, set);
+ if (set->Advertise) DeadvertiseInterface(m, set, kDeadvertiseFlag_All);
// If we have any cache records received on this interface that went away, then re-verify them.
// In some versions of OS X the IPv6 address remains on an interface even when the interface is turned off,
@@ -13332,52 +13423,6 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se
mDNS_Unlock(m);
}
-mDNSlocal void SetAnonInfoSRS(ServiceRecordSet *sr, int NumSubTypes)
-{
- int i, len;
-
- if (!sr->AnonData)
- return;
-
- len = mDNSPlatformStrLen(sr->AnonData);
- if (sr->RR_PTR.resrec.AnonInfo)
- {
- LogMsg("SetAnonInfoSRS: Freeing AnonInfo for PTR record %##s, should have been freed already", sr->RR_PTR.resrec.name->c);
- FreeAnonInfo(sr->RR_PTR.resrec.AnonInfo);
- }
- sr->RR_PTR.resrec.AnonInfo = AllocateAnonInfo(sr->RR_PTR.resrec.name, sr->AnonData, len, mDNSNULL);
- for (i=0; i<NumSubTypes; i++)
- {
- if (sr->SubTypes[i].resrec.AnonInfo)
- {
- LogMsg("SetAnonInfoSRS: Freeing AnonInfo for subtype record %##s, should have been freed already", sr->SubTypes[i].resrec.name->c);
- FreeAnonInfo(sr->SubTypes[i].resrec.AnonInfo);
- }
- sr->SubTypes[i].resrec.AnonInfo = AllocateAnonInfo(sr->SubTypes[i].resrec.name, sr->AnonData, len, mDNSNULL);
- }
-}
-
-mDNSlocal void ResetAnonInfoSRS(ServiceRecordSet *sr, int NumSubTypes)
-{
- int i;
-
- if (!sr->AnonData)
- return;
- if (sr->RR_PTR.resrec.AnonInfo)
- {
- FreeAnonInfo(sr->RR_PTR.resrec.AnonInfo);
- sr->RR_PTR.resrec.AnonInfo = mDNSNULL;
- }
- for (i=0; i<NumSubTypes; i++)
- {
- if (sr->SubTypes[i].resrec.AnonInfo)
- {
- FreeAnonInfo(sr->SubTypes[i].resrec.AnonInfo);
- sr->SubTypes[i].resrec.AnonInfo = mDNSNULL;
- }
- }
-}
-
mDNSlocal void ServiceCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
{
ServiceRecordSet *sr = (ServiceRecordSet *)rr->RecordContext;
@@ -13423,7 +13468,6 @@ mDNSlocal void ServiceCallback(mDNS *const m, AuthRecord *const rr, mStatus resu
if (e->r.resrec.RecordType != kDNSRecordTypeUnregistered) return;
e = e->next;
}
- ResetAnonInfoSRS(sr, sr->NumSubTypes);
// If this ServiceRecordSet was forcibly deregistered, and now its memory is ready for reuse,
// then we can now report the NameConflict to the client
@@ -13468,18 +13512,6 @@ mDNSlocal AuthRecType setAuthRecType(mDNSInterfaceID InterfaceID, mDNSu32 flags)
return artype;
}
-// Used to derive the original D2D specific flags specified by the client in the registration
-// when we don't have access to the original flag (kDNSServiceFlags*) values.
-mDNSexport mDNSu32 deriveD2DFlagsFromAuthRecType(AuthRecType authRecType)
-{
- mDNSu32 flags = 0;
- if ((authRecType == AuthRecordAnyIncludeP2P) || (authRecType == AuthRecordAnyIncludeAWDLandP2P))
- flags |= kDNSServiceFlagsIncludeP2P;
- else if ((authRecType == AuthRecordAnyIncludeAWDL) || (authRecType == AuthRecordAnyIncludeAWDLandP2P))
- flags |= kDNSServiceFlagsIncludeAWDL;
- return flags;
-}
-
// Note:
// Name is first label of domain name (any dots in the name are actual dots, not label separators)
// Type is service type (e.g. "_ipp._tcp.")
@@ -13497,7 +13529,6 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
{
mStatus err;
mDNSu32 i;
- mDNSu32 hostTTL;
AuthRecType artype;
mDNSu8 recordType = (flags & kDNSServiceFlagsKnownUnique) ? kDNSRecordTypeKnownUnique : kDNSRecordTypeUnique;
@@ -13522,12 +13553,7 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
sr->RR_PTR.AuthFlags = AuthFlagsWakeOnly;
}
- if (SameDomainName(type, (const domainname *) "\x4" "_ubd" "\x4" "_tcp"))
- hostTTL = kHostNameSmallTTL;
- else
- hostTTL = kHostNameTTL;
-
- mDNS_SetupResourceRecord(&sr->RR_SRV, mDNSNULL, InterfaceID, kDNSType_SRV, hostTTL, recordType, artype, ServiceCallback, sr);
+ mDNS_SetupResourceRecord(&sr->RR_SRV, mDNSNULL, InterfaceID, kDNSType_SRV, kHostNameTTL, recordType, artype, ServiceCallback, sr);
mDNS_SetupResourceRecord(&sr->RR_TXT, txtrdata, InterfaceID, kDNSType_TXT, kStandardTTL, recordType, artype, ServiceCallback, sr);
// If port number is zero, that means the client is really trying to do a RegisterNoSuchService
@@ -13574,8 +13600,6 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
sr->SubTypes[i].Additional2 = &sr->RR_TXT;
}
- SetAnonInfoSRS(sr, NumSubTypes);
-
// 3. Set up the SRV record rdata.
sr->RR_SRV.resrec.rdata->u.srv.priority = 0;
sr->RR_SRV.resrec.rdata->u.srv.weight = 0;
@@ -13737,6 +13761,9 @@ mDNSexport mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordS
debugf("%##s service renamed from \"%#s\" to \"%#s\"", type.c, name1.c, newname->c);
else debugf("%##s service (domain %##s) renamed from \"%#s\" to \"%#s\"",type.c, domain.c, name1.c, newname->c);
+ // If there's a pending TXT record update at this point, which can happen if a DNSServiceUpdateRecord() call was made
+ // after the TXT record's deregistration, execute it now, otherwise it will be lost during the service re-registration.
+ if (sr->RR_TXT.NewRData) CompleteRDataUpdate(m, &sr->RR_TXT);
err = mDNS_RegisterService(m, sr, newname, &type, &domain,
host, sr->RR_SRV.resrec.rdata->u.srv.port,
(sr->RR_TXT.resrec.rdata != &sr->RR_TXT.rdatastorage) ? sr->RR_TXT.resrec.rdata : mDNSNULL,
@@ -13799,7 +13826,6 @@ mDNSexport mStatus mDNS_DeregisterService_drt(mDNS *const m, ServiceRecordSet *s
// SRV, TXT, or Extra records could have already been automatically deregistered, and that's okay
mDNS_Deregister_internal(m, &sr->RR_SRV, mDNS_Dereg_repeat);
mDNS_Deregister_internal(m, &sr->RR_TXT, mDNS_Dereg_repeat);
-
mDNS_Deregister_internal(m, &sr->RR_ADV, drt);
// We deregister all of the extra records, but we leave the sr->Extras list intact
@@ -14066,10 +14092,10 @@ mDNSlocal void mDNSCoreReceiveRawND(mDNS *const m, const mDNSEthAddr *const sha,
static const char msg3[] = "Creating Local NDP Cache entry ";
static const char msg4[] = "Answering NDP Request from ";
static const char msg5[] = "Answering NDP Probe from ";
- const char *const msg = sha && mDNSSameEthAddress(sha, &rr->WakeUp.IMAC) ? msg1 :
- (rr->AnnounceCount == InitialAnnounceCount) ? msg2 :
- sha && mDNSSameEthAddress(sha, &intf->MAC) ? msg3 :
- spa && mDNSIPv6AddressIsZero(*spa) ? msg4 : msg5;
+ const char *const msg = mDNSSameEthAddress(sha, &rr->WakeUp.IMAC) ? msg1 :
+ (rr->AnnounceCount == InitialAnnounceCount) ? msg2 :
+ mDNSSameEthAddress(sha, &intf->MAC) ? msg3 :
+ mDNSIPv6AddressIsZero(*spa) ? msg4 : msg5;
LogSPS("%-7s %s %.6a %.16a for %.16a -- H-MAC %.6a I-MAC %.6a %s",
intf->ifname, msg, sha, spa, &ndp->target, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, rr));
if (msg == msg1)
@@ -14337,7 +14363,7 @@ mDNSexport void mDNSCoreReceiveRawPacket(mDNS *const m, const mDNSu8 *const p, c
const mDNSu8 *const trans = p + 14 + (pkt->v4.vlen & 0xF) * 4;
const mDNSu8 * transEnd = p + 14 + mDNSVal16(pkt->v4.totlen);
if (transEnd > end) transEnd = end;
- debugf("Got IPv4 %02X from %.4a to %.4a", pkt->v4.protocol, &pkt->v4.src, &pkt->v4.dst);
+ debugf("Got IPv4 %02X from %.4a to %.4a", pkt->v4.protocol, &pkt->v4.src.b, &pkt->v4.dst.b);
src.type = mDNSAddrType_IPv4; src.ip.v4 = pkt->v4.src;
dst.type = mDNSAddrType_IPv4; dst.ip.v4 = pkt->v4.dst;
if (transEnd >= trans + RequiredCapLen(pkt->v4.protocol))
@@ -14347,7 +14373,7 @@ mDNSexport void mDNSCoreReceiveRawPacket(mDNS *const m, const mDNSu8 *const p, c
else if (end >= p+54 && mDNSSameOpaque16(eth->ethertype, Ethertype_IPv6))
{
const mDNSu8 *const trans = p + 54;
- debugf("Got IPv6 %02X from %.16a to %.16a", pkt->v6.pro, &pkt->v6.src, &pkt->v6.dst);
+ debugf("Got IPv6 %02X from %.16a to %.16a", pkt->v6.pro, &pkt->v6.src.b, &pkt->v6.dst.b);
src.type = mDNSAddrType_IPv6; src.ip.v6 = pkt->v6.src;
dst.type = mDNSAddrType_IPv6; dst.ip.v6 = pkt->v6.dst;
if (end >= trans + RequiredCapLen(pkt->v6.pro))
@@ -14484,7 +14510,6 @@ mDNSlocal mStatus mDNS_InitStorage(mDNS *const m, mDNS_PlatformSupport *const p,
m->MainCallback = Callback;
m->MainContext = Context;
m->rec.r.resrec.RecordType = 0;
- m->rec.r.resrec.AnonInfo = mDNSNULL;
// For debugging: To catch and report locking failures
m->mDNS_busy = 0;
@@ -14514,12 +14539,11 @@ mDNSlocal mStatus mDNS_InitStorage(mDNS *const m, mDNS_PlatformSupport *const p,
m->NextScheduledStopTime = timenow + FutureTime;
m->NextBLEServiceTime = 0; // zero indicates inactive
-#if BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
m->NextBonjourDisableTime = 0; // Timer active when non zero.
- m->BonjourEnabled = 0; // Set when Bonjour on Demand is enabled and Bonjour is currently enabled.
-#endif // BONJOUR_ON_DEMAND
+ m->BonjourEnabled = 0; // Set when Bonjour on Demand is enabled and Bonjour is currently enabled.
+#endif
- m->DelayConflictProcessing = MAX_CONFLICT_PROCESSING_DELAYS;
m->RandomQueryDelay = 0;
m->RandomReconfirmDelay = 0;
m->PktNum = 0;
@@ -14545,7 +14569,6 @@ mDNSlocal mStatus mDNS_InitStorage(mDNS *const m, mDNS_PlatformSupport *const p,
m->LocalOnlyQuestions = mDNSNULL;
m->NewLocalOnlyQuestions = mDNSNULL;
m->RestartQuestion = mDNSNULL;
- m->ValidationQuestion = mDNSNULL;
m->rrcache_size = 0;
m->rrcache_totalused = 0;
m->rrcache_active = 0;
@@ -14568,6 +14591,9 @@ mDNSlocal mStatus mDNS_InitStorage(mDNS *const m, mDNS_PlatformSupport *const p,
m->hostlabel.c[0] = 0;
m->nicelabel.c[0] = 0;
m->MulticastHostname.c[0] = 0;
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ m->RandomizedHostname.c[0] = 0;
+#endif
m->HIHardware.c[0] = 0;
m->HISoftware.c[0] = 0;
m->ResourceRecords = mDNSNULL;
@@ -14584,7 +14610,9 @@ mDNSlocal mStatus mDNS_InitStorage(mDNS *const m, mDNS_PlatformSupport *const p,
m->NextuDNSEvent = timenow + FutureTime;
m->NextSRVUpdate = timenow + FutureTime;
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
m->DNSServers = mDNSNULL;
+#endif
m->Router = zeroAddr;
m->AdvertisedV4 = zeroAddr;
@@ -14596,14 +14624,13 @@ mDNSlocal mStatus mDNS_InitStorage(mDNS *const m, mDNS_PlatformSupport *const p,
m->StaticHostname.c[0] = 0;
m->FQDN.c[0] = 0;
m->Hostnames = mDNSNULL;
- m->AutoTunnelNAT.clientContext = mDNSNULL;
m->WABBrowseQueriesCount = 0;
m->WABLBrowseQueriesCount = 0;
m->WABRegQueriesCount = 0;
m->AutoTargetServices = 1;
-#if BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
m->NumAllInterfaceRecords = 0;
m->NumAllInterfaceQuestions = 0;
#endif
@@ -14649,17 +14676,17 @@ mDNSlocal mStatus mDNS_InitStorage(mDNS *const m, mDNS_PlatformSupport *const p,
m->DNSPushZones = mDNSNULL;
#endif
-#if APPLE_OSX_mDNSResponder
- m->TunnelClients = mDNSNULL;
-
-#if !NO_WCF
- CHECK_WCF_FUNCTION(WCFConnectionNew)
+#if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
+ if (WCFConnectionNew)
{
m->WCF = WCFConnectionNew();
if (!m->WCF) { LogMsg("WCFConnectionNew failed"); return -1; }
}
#endif
-
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+ result = init_and_load_trust_anchors();
+ if (result != mStatus_NoError) return(result);
#endif
return(result);
@@ -14673,6 +14700,10 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
if (result != mStatus_NoError)
return(result);
+#if MDNS_MALLOC_DEBUGGING
+ static mDNSListValidator lv;
+ mDNSPlatformAddListValidator(&lv, mDNS_ValidateLists, "mDNS_ValidateLists", m);
+#endif
result = mDNSPlatformInit(m);
#ifndef UNICAST_DISABLED
@@ -14717,7 +14748,8 @@ mDNSlocal void DynDNSHostNameCallback(mDNS *const m, AuthRecord *const rr, mStat
mDNSPlatformDynDNSHostNameStatusChanged(rr->resrec.name, result);
}
-mDNSlocal void PurgeOrReconfirmCacheRecord(mDNS *const m, CacheRecord *cr, const DNSServer * const ptr, mDNSBool lameduck)
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+mDNSlocal void PurgeOrReconfirmCacheRecord(mDNS *const m, CacheRecord *cr)
{
mDNSBool purge = cr->resrec.RecordType == kDNSRecordTypePacketNegative ||
cr->resrec.rrtype == kDNSType_A ||
@@ -14725,12 +14757,11 @@ mDNSlocal void PurgeOrReconfirmCacheRecord(mDNS *const m, CacheRecord *cr, const
cr->resrec.rrtype == kDNSType_SRV ||
cr->resrec.rrtype == kDNSType_CNAME;
- (void) lameduck;
- (void) ptr;
- debugf("PurgeOrReconfirmCacheRecord: %s cache record due to %s server %p %#a:%d (%##s): %s",
+ debugf("PurgeOrReconfirmCacheRecord: %s cache record due to server %#a:%d (%##s): %s",
purge ? "purging" : "reconfirming",
- lameduck ? "lame duck" : "new",
- ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c, CRDisplayString(m, cr));
+ cr->resrec.rDNSServer ? &cr->resrec.rDNSServer->addr : mDNSNULL,
+ cr->resrec.rDNSServer ? mDNSVal16(cr->resrec.rDNSServer->port) : -1,
+ cr->resrec.rDNSServer ? cr->resrec.rDNSServer->domain.c : mDNSNULL, CRDisplayString(m, cr));
if (purge)
{
@@ -14743,86 +14774,23 @@ mDNSlocal void PurgeOrReconfirmCacheRecord(mDNS *const m, CacheRecord *cr, const
mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
}
}
+#endif
mDNSlocal void mDNS_PurgeBeforeResolve(mDNS *const m, DNSQuestion *q)
{
CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname);
CacheRecord *rp;
- mDNSu8 validatingResponse = 0;
-
- // For DNSSEC questions, purge the corresponding RRSIGs also.
- if (DNSSECQuestion(q))
- {
- validatingResponse = q->ValidatingResponse;
- q->ValidatingResponse = mDNStrue;
- }
for (rp = cg ? cg->members : mDNSNULL; rp; rp = rp->next)
{
- if (SameNameRecordAnswersQuestion(&rp->resrec, q))
+ if (SameNameCacheRecordAnswersQuestion(rp, q))
{
LogInfo("mDNS_PurgeBeforeResolve: Flushing %s", CRDisplayString(m, rp));
mDNS_PurgeCacheResourceRecord(m, rp);
}
}
- if (DNSSECQuestion(q))
- {
- q->ValidatingResponse = validatingResponse;
- }
-}
-
-// For DNSSEC question, we need the DNSSEC records also. If the cache does not
-// have the DNSSEC records, we need to re-issue the question with EDNS0/DO bit set.
-// Just re-issuing the question for RRSIGs does not work in practice as the response
-// may not contain the RRSIGs whose typeCovered field matches the question's qtype.
-//
-// For negative responses, we need the NSECs to prove the non-existence. If we don't
-// have the cached NSECs, purge them. For positive responses, if we don't have the
-// RRSIGs and if we have not already issued the question with EDNS0/DO bit set, purge
-// them.
-mDNSlocal void CheckForDNSSECRecords(mDNS *const m, DNSQuestion *q)
-{
- CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname);
- CacheRecord *rp;
-
- for (rp = cg ? cg->members : mDNSNULL; rp; rp = rp->next)
- {
- if (SameNameRecordAnswersQuestion(&rp->resrec, q))
- {
- if (rp->resrec.RecordType != kDNSRecordTypePacketNegative || !rp->nsec)
- {
- if (!rp->CRDNSSECQuestion)
- {
- LogInfo("CheckForDNSSECRecords: Flushing %s", CRDisplayString(m, rp));
- mDNS_PurgeCacheResourceRecord(m, rp);
- }
- }
- }
- }
-}
-
-// Check for a positive unicast response to the question but with qtype
-mDNSexport mDNSBool mDNS_CheckForCacheRecord(mDNS *const m, DNSQuestion *q, mDNSu16 qtype)
-{
- DNSQuestion question;
- CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname);
- CacheRecord *rp;
-
- // Create an identical question but with qtype
- mDNS_SetupQuestion(&question, q->InterfaceID, &q->qname, qtype, mDNSNULL, mDNSNULL);
- question.qDNSServer = q->qDNSServer;
-
- for (rp = cg ? cg->members : mDNSNULL; rp; rp = rp->next)
- {
- if (!rp->resrec.InterfaceID && rp->resrec.RecordType != kDNSRecordTypePacketNegative &&
- SameNameRecordAnswersQuestion(&rp->resrec, &question))
- {
- LogInfo("mDNS_CheckForCacheRecord: Found %s", CRDisplayString(m, rp));
- return mDNStrue;
- }
- }
- return mDNSfalse;
}
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
mDNSexport void DNSServerChangeForQuestion(mDNS *const m, DNSQuestion *q, DNSServer *new)
{
DNSQuestion *qptr;
@@ -14841,24 +14809,28 @@ mDNSexport void DNSServerChangeForQuestion(mDNS *const m, DNSQuestion *q, DNSSer
if (qptr->DuplicateOf == q) { qptr->validDNSServers = q->validDNSServers; qptr->qDNSServer = new; }
}
}
+#endif
mDNSlocal void SetConfigState(mDNS *const m, mDNSBool delete)
{
McastResolver *mr;
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
DNSServer *ptr;
+#endif
if (delete)
{
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
for (ptr = m->DNSServers; ptr; ptr = ptr->next)
{
ptr->penaltyTime = 0;
- NumUnicastDNSServers--;
- ptr->flags |= DNSServer_FlagDelete;
-#if APPLE_OSX_mDNSResponder
- if (ptr->flags & DNSServer_FlagUnreachable)
+ ptr->flags |= DNSServerFlag_Delete;
+#if MDNSRESPONDER_SUPPORTS(APPLE, SYMPTOMS)
+ if (ptr->flags & DNSServerFlag_Unreachable)
NumUnreachableDNSServers--;
#endif
}
+#endif
// We handle the mcast resolvers here itself as mDNSPlatformSetDNSConfig looks at
// mcast resolvers. Today we get both mcast and ucast configuration using the same
// API
@@ -14867,16 +14839,17 @@ mDNSlocal void SetConfigState(mDNS *const m, mDNSBool delete)
}
else
{
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
for (ptr = m->DNSServers; ptr; ptr = ptr->next)
{
ptr->penaltyTime = 0;
- NumUnicastDNSServers++;
- ptr->flags &= ~DNSServer_FlagDelete;
-#if APPLE_OSX_mDNSResponder
- if (ptr->flags & DNSServer_FlagUnreachable)
+ ptr->flags &= ~DNSServerFlag_Delete;
+#if MDNSRESPONDER_SUPPORTS(APPLE, SYMPTOMS)
+ if (ptr->flags & DNSServerFlag_Unreachable)
NumUnreachableDNSServers++;
#endif
}
+#endif
for (mr = m->McastResolvers; mr; mr = mr->next)
mr->flags &= ~McastResolver_FlagDelete;
}
@@ -14899,19 +14872,27 @@ mDNSlocal void SetDynDNSHostNameIfChanged(mDNS *const m, domainname *const fqdn)
}
}
+// Even though this is called “Setup” it is not called just once at startup.
+// It’s actually called multiple times, every time there’s a configuration change.
mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
{
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
mDNSu32 slot;
CacheGroup *cg;
CacheRecord *cr;
- mDNSBool Restart = mDNSfalse;
+#endif
mDNSAddr v4, v6, r;
domainname fqdn;
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
DNSServer *ptr, **p = &m->DNSServers;
const DNSServer *oldServers = m->DNSServers;
DNSQuestion *q;
+#endif
McastResolver *mr, **mres = &m->McastResolvers;
-
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH) && !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ DNSPushNotificationServer **psp;
+#endif
+
debugf("uDNS_SetupDNSConfig: entry");
// Let the platform layer get the current DNS information and setup the WAB queries if needed.
@@ -14956,6 +14937,9 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
}
}
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ Querier_ProcessDNSServiceChanges();
+#else
// Update our qDNSServer pointers before we go and free the DNSServer object memory
//
// All non-scoped resolvers share the same resGroupID. At no point in time a cache entry using DNSServer
@@ -14983,101 +14967,118 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
// cache records and as the resGroupID is different, you can't use the cache record from the scoped DNSServer to answer the
// non-scoped question and vice versa.
//
-#if USE_DNS64
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
DNS64RestartQuestions(m);
#endif
- for (q = m->Questions; q; q=q->next)
+
+ // First, restart questions whose suppression status will change. The suppression status of each question in a given
+ // question set, i.e., a non-duplicate question and all of its duplicates, if any, may or may not change. For example,
+ // a suppressed (or non-suppressed) question that is currently a duplicate of a suppressed (or non-suppressed) question
+ // may become a non-suppressed (or suppressed) question, while the question that it's a duplicate of may remain
+ // suppressed (or non-suppressed).
+ for (q = m->Questions; q; q = q->next)
{
- if (!mDNSOpaque16IsZero(q->TargetQID))
- {
- DNSServer *s, *t;
- DNSQuestion *qptr;
- if (q->DuplicateOf) continue;
- SetValidDNSServers(m, q);
- q->triedAllServersOnce = 0;
- s = GetServerForQuestion(m, q);
- t = q->qDNSServer;
- if (t != s)
- {
- mDNSBool old, new;
- mDNSIPPort tport, sport;
-
- if (t)
- tport = t->port;
- else
- tport = zeroIPPort;
+ DNSServer *s;
+ const DNSServer *t;
+ mDNSBool oldSuppressed;
- if (s)
- sport = s->port;
- else
- sport = zeroIPPort;
- // If DNS Server for this question has changed, reactivate it
- LogInfo("uDNS_SetupDNSConfig: Updating DNS Server from %#a:%d (%##s) to %#a:%d (%##s) for question %##s (%s) (scope:%p)",
- t ? &t->addr : mDNSNULL, mDNSVal16(tport), t ? t->domain.c : (mDNSu8*)"",
- s ? &s->addr : mDNSNULL, mDNSVal16(sport), s ? s->domain.c : (mDNSu8*)"",
- q->qname.c, DNSTypeName(q->qtype), q->InterfaceID);
-
- old = q->SuppressQuery;
- new = ShouldSuppressUnicastQuery(m, q, s);
- if (old != new)
- {
- // Changing the DNS server affected the SuppressQuery status. We need to
- // deliver RMVs for the previous ADDs (if any) before switching to the new
- // DNSServer. To keep it simple, we walk all the questions and mark them
- // to be restarted and then handle all of them at once.
- q->Restart = 1;
- q->SuppressQuery = new;
- for (qptr = q->next ; qptr; qptr = qptr->next)
- {
- if (qptr->DuplicateOf == q)
- qptr->Restart = 1;
- }
- Restart = mDNStrue;
+ if (mDNSOpaque16IsZero(q->TargetQID)) continue;
+
+ SetValidDNSServers(m, q);
+ q->triedAllServersOnce = mDNSfalse;
+ s = GetServerForQuestion(m, q);
+ t = q->qDNSServer;
+ if (s != t)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] uDNS_SetupDNSConfig: Updating DNS server from " PRI_IP_ADDR ":%d (" PRI_DM_NAME ") to "
+ PRI_IP_ADDR ":%d (" PRI_DM_NAME ") for question " PRI_DM_NAME " (" PUB_S ") (scope:%p)",
+ q->request_id, mDNSVal16(q->TargetQID),
+ t ? &t->addr : mDNSNULL, mDNSVal16(t ? t->port : zeroIPPort), DM_NAME_PARAM(t ? &t->domain : mDNSNULL),
+ s ? &s->addr : mDNSNULL, mDNSVal16(s ? s->port : zeroIPPort), DM_NAME_PARAM(s ? &s->domain : mDNSNULL),
+ DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype), q->InterfaceID);
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
+ // If this question had a DNS Push server associated with it, substitute the new server for the
+ // old one. If there is no new server, then we'll clean up the push server later.
+ if (!q->DuplicateOf && (q->dnsPushServer != mDNSNULL))
+ {
+ if (q->dnsPushServer->qDNSServer == t)
+ {
+ q->dnsPushServer->qDNSServer = s; // which might be null
}
- else
+ // If it is null, do the accounting and drop the push server.
+ if (q->dnsPushServer->qDNSServer == mDNSNULL)
{
- DNSServerChangeForQuestion(m, q, s);
- q->unansweredQueries = 0;
-
- // If we had sent a query out to DNSServer "t" and we are changing to "s", we
- // need to ignore the responses coming back from "t" as the DNS configuration
- // has changed e.g., when a new interface is coming up and that becomes the primary
- // interface, we switch to the DNS servers configured for the primary interface. In
- // this case, we should not accept responses associated with the previous interface as
- // the "name" could resolve differently on this new primary interface. Hence, discard
- // in-flight responses.
- q->TargetQID = mDNS_NewMessageID(m);
-
- if (!QuerySuppressed(q))
- {
- debugf("uDNS_SetupDNSConfig: Activating query %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
- ActivateUnicastQuery(m, q, mDNStrue);
- // ActivateUnicastQuery is called for duplicate questions also as it does something
- // special for AutoTunnel questions
- for (qptr = q->next ; qptr; qptr = qptr->next)
- {
- if (qptr->DuplicateOf == q) ActivateUnicastQuery(m, qptr, mDNStrue);
- }
- }
+ DNSPushReconcileConnection(m, q);
}
}
- else
+#endif
+ }
+ oldSuppressed = q->Suppressed;
+ q->Suppressed = ShouldSuppressUnicastQuery(q, s);
+ if (!q->Suppressed != !oldSuppressed) q->Restart = mDNStrue;
+ }
+ RestartUnicastQuestions(m);
+
+ // Now, change the server for each question set, if necessary. Note that questions whose suppression status changed
+ // have already had their server changed by being restarted.
+ for (q = m->Questions; q; q = q->next)
+ {
+ DNSServer *s;
+ const DNSServer *t;
+
+ if (mDNSOpaque16IsZero(q->TargetQID) || q->DuplicateOf) continue;
+
+ SetValidDNSServers(m, q);
+ q->triedAllServersOnce = mDNSfalse;
+ s = GetServerForQuestion(m, q);
+ t = q->qDNSServer;
+ DNSServerChangeForQuestion(m, q, s);
+ if (s == t) continue;
+
+ q->Suppressed = ShouldSuppressUnicastQuery(q, s);
+ q->unansweredQueries = 0;
+ q->TargetQID = mDNS_NewMessageID(m);
+ if (!q->Suppressed) ActivateUnicastQuery(m, q, mDNStrue);
+ }
+
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
+ // The above code may have found some DNS Push servers that are no longer valid. Now that we
+ // are done running through the code, we need to drop our connections to those servers.
+ // When we get here, any such servers should have zero questions associated with them.
+ for (psp = &m->DNSPushServers; *psp != mDNSNULL; )
+ {
+ DNSPushNotificationServer *server = *psp;
+
+ // It's possible that a push server whose DNS server has been deleted could be still connected but
+ // not referenced by any questions. In this case, we just delete the push server rather than trying
+ // to figure out with which DNS server (if any) to associate it.
+ if (server->qDNSServer != mDNSNULL && server->qDNSServer->flags & DNSServerFlag_Delete)
+ {
+ server->qDNSServer = mDNSNULL;
+ }
+
+ if (server->qDNSServer == mDNSNULL)
+ {
+ // This would be a programming error, so should never happen.
+ if (server->numberOfQuestions != 0)
{
- mDNSIPPort zp = zeroIPPort;
- debugf("uDNS_SetupDNSConfig: Not Updating DNS server question %p %##s (%s) DNS server %#a:%d %p %d",
- q, q->qname.c, DNSTypeName(q->qtype), t ? &t->addr : mDNSNULL, mDNSVal16(t ? t->port : zp), q->DuplicateOf, q->SuppressUnusable);
- for (qptr = q->next ; qptr; qptr = qptr->next)
- if (qptr->DuplicateOf == q) { qptr->validDNSServers = q->validDNSServers; qptr->qDNSServer = q->qDNSServer; }
+ LogInfo("uDNS_SetupDNSConfig: deleting push server %##s that has questions.", &server->serverName);
}
+ DNSPushServerDrop(server);
+ *psp = server->next;
+ mDNSPlatformMemFree(server);
+ }
+ else
+ {
+ psp = &(*psp)->next;
}
}
- if (Restart)
- RestartUnicastQuestions(m);
+#endif
FORALL_CACHERECORDS(slot, cg, cr)
{
- if (cr->resrec.InterfaceID)
- continue;
+ if (cr->resrec.InterfaceID) continue;
// We already walked the questions and restarted/reactivated them if the dns server
// change affected the question. That should take care of updating the cache. But
@@ -15090,111 +15091,84 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
// the questions if they were suppressed (see above). To keep it simple, we walk
// all the cache entries to make sure that there are no stale entries. We use the
// active question's InterfaceID/ServiceID for looking up the right DNS server.
- // Note that the unscoped value for ServiceID is -1.
//
// Note: If GetServerForName returns NULL, it could either mean that there are no
// DNS servers or no matching DNS servers for this question. In either case,
// the cache should get purged below when we process deleted DNS servers.
- ptr = GetServerForName(m, cr->resrec.name,
- (cr->CRActiveQuestion ? cr->CRActiveQuestion->InterfaceID : mDNSNULL),
- (cr->CRActiveQuestion ? cr->CRActiveQuestion->ServiceID : -1));
-
- // Purge or Reconfirm if this cache entry would use the new DNS server
- if (ptr && (ptr != cr->resrec.rDNSServer))
+ if (cr->CRActiveQuestion)
{
- // As the DNSServers for this cache record is not the same anymore, we don't
- // want any new questions to pick this old value. If there is no active question,
- // we can't possibly re-confirm, so purge in that case. If it is a DNSSEC question,
- // purge the cache as the DNSSEC capabilities of the DNS server may have changed.
-
- if (cr->CRActiveQuestion == mDNSNULL || DNSSECQuestion(cr->CRActiveQuestion))
+ // Purge or Reconfirm if this cache entry would use the new DNS server
+ ptr = GetServerForName(m, cr->resrec.name, cr->CRActiveQuestion->InterfaceID, cr->CRActiveQuestion->ServiceID);
+ if (ptr && (ptr != cr->resrec.rDNSServer))
{
- LogInfo("uDNS_SetupDNSConfig: Purging Resourcerecord %s, New DNS server %#a , Old DNS server %#a", CRDisplayString(m, cr),
- &ptr->addr, (cr->resrec.rDNSServer != mDNSNULL ? &cr->resrec.rDNSServer->addr : mDNSNULL));
- cr->resrec.mortality = Mortality_Mortal;
- mDNS_PurgeCacheResourceRecord(m, cr);
+ LogInfo("uDNS_SetupDNSConfig: Purging/Reconfirming Resourcerecord %s, New DNS server %#a, Old DNS server %#a",
+ CRDisplayString(m, cr), &ptr->addr,
+ cr->resrec.rDNSServer ? &cr->resrec.rDNSServer->addr : mDNSNULL);
+ PurgeOrReconfirmCacheRecord(m, cr);
+
+ // If a cache record's DNSServer pointer is NULL, but its active question got a DNSServer in this DNS configuration
+ // update, then use its DNSServer. This way, the active question and its duplicates don't miss out on RMV events.
+ if (!cr->resrec.rDNSServer && cr->CRActiveQuestion->qDNSServer)
+ {
+ LogInfo("uDNS_SetupDNSConfig: Using active question's DNS server %#a for cache record %s", &cr->CRActiveQuestion->qDNSServer->addr, CRDisplayString(m, cr));
+ cr->resrec.rDNSServer = cr->CRActiveQuestion->qDNSServer;
+ }
}
- else
+
+ if (cr->resrec.rDNSServer && cr->resrec.rDNSServer->flags & DNSServerFlag_Delete)
{
- LogInfo("uDNS_SetupDNSConfig: Purging/Reconfirming Resourcerecord %s, New DNS server %#a, Old DNS server %#a", CRDisplayString(m, cr),
- &ptr->addr, (cr->resrec.rDNSServer != mDNSNULL ? &cr->resrec.rDNSServer->addr : mDNSNULL));
- PurgeOrReconfirmCacheRecord(m, cr, ptr, mDNSfalse);
+ DNSQuestion *qptr = cr->CRActiveQuestion;
+ if (qptr->qDNSServer == cr->resrec.rDNSServer)
+ {
+ LogMsg("uDNS_SetupDNSConfig: ERROR!! Cache Record %s Active question %##s (%s) (scope:%p) pointing to DNSServer Address %#a"
+ " to be freed", CRDisplayString(m, cr),
+ qptr->qname.c, DNSTypeName(qptr->qtype), qptr->InterfaceID,
+ &cr->resrec.rDNSServer->addr);
+ qptr->validDNSServers = zeroOpaque128;
+ qptr->qDNSServer = mDNSNULL;
+ cr->resrec.rDNSServer = mDNSNULL;
+ }
+ else
+ {
+ LogInfo("uDNS_SetupDNSConfig: Cache Record %s, Active question %##s (%s) (scope:%p), pointing to DNSServer %#a (to be deleted),"
+ " resetting to question's DNSServer Address %#a", CRDisplayString(m, cr),
+ qptr->qname.c, DNSTypeName(qptr->qtype), qptr->InterfaceID,
+ &cr->resrec.rDNSServer->addr,
+ qptr->qDNSServer ? &qptr->qDNSServer->addr : mDNSNULL);
+ cr->resrec.rDNSServer = qptr->qDNSServer;
+ }
+ PurgeOrReconfirmCacheRecord(m, cr);
}
}
-
- // If a cache record's DNSServer pointer is NULL, but its active question got a DNSServer in this DNS configuration
- // update, then use its DNSServer. This way, the active question and its duplicates don't miss out on RMV events.
- if (!cr->resrec.rDNSServer && cr->CRActiveQuestion && cr->CRActiveQuestion->qDNSServer)
+ else if (!cr->resrec.rDNSServer || cr->resrec.rDNSServer->flags & DNSServerFlag_Delete)
{
- cr->resrec.rDNSServer = cr->CRActiveQuestion->qDNSServer;
- LogInfo("uDNS_SetupDNSConfig: Using active question's DNS server %#a for cache record %s", &cr->resrec.rDNSServer->addr, CRDisplayString(m, cr));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+ "uDNS_SetupDNSConfig: Purging Resourcerecord " PRI_S ", DNS server " PUB_S " " PRI_IP_ADDR " " PUB_S,
+ CRDisplayString(m, cr), !cr->resrec.rDNSServer ? "(to be deleted)" : "",
+ cr->resrec.rDNSServer ? &cr->resrec.rDNSServer->addr : mDNSNULL,
+ cr->resrec.rDNSServer ? DNSScopeToString(cr->resrec.rDNSServer->scopeType) : "" );
+ cr->resrec.rDNSServer = mDNSNULL;
+ mDNS_PurgeCacheResourceRecord(m, cr);
}
}
+ // Delete all the DNS servers that are flagged for deletion
while (*p)
{
- if (((*p)->flags & DNSServer_FlagDelete) != 0)
+ if (((*p)->flags & DNSServerFlag_Delete) != 0)
{
- // Scan our cache, looking for uDNS records that we would have queried this server for.
- // We reconfirm any records that match, because in this world of split DNS, firewalls, etc.
- // different DNS servers can give different answers to the same question.
ptr = *p;
- FORALL_CACHERECORDS(slot, cg, cr)
- {
- if (cr->resrec.InterfaceID) continue;
- if (cr->resrec.rDNSServer == ptr)
- {
- // If we don't have an active question for this cache record, neither Purge can
- // generate RMV events nor Reconfirm can send queries out. Just set the DNSServer
- // pointer on the record NULL so that we don't point to freed memory (We might dereference
- // DNSServer pointers from resource record for logging purposes).
- //
- // If there is an active question, point to its DNSServer as long as it does not point to the
- // freed one. We already went through the questions above and made them point at either the
- // new server or NULL if there is no server.
-
- if (cr->CRActiveQuestion)
- {
- DNSQuestion *qptr = cr->CRActiveQuestion;
-
- if (qptr->qDNSServer == ptr)
- {
- LogMsg("uDNS_SetupDNSConfig: ERROR!! Cache Record %s Active question %##s (%s) (scope:%p) pointing to DNSServer Address %#a"
- " to be freed", CRDisplayString(m, cr), qptr->qname.c, DNSTypeName(qptr->qtype), qptr->InterfaceID, &ptr->addr);
- qptr->validDNSServers = zeroOpaque128;
- qptr->qDNSServer = mDNSNULL;
- cr->resrec.rDNSServer = mDNSNULL;
- }
- else
- {
- LogInfo("uDNS_SetupDNSConfig: Cache Record %s, Active question %##s (%s) (scope:%p), pointing to DNSServer %#a (to be deleted),"
- " resetting to question's DNSServer Address %#a", CRDisplayString(m, cr), qptr->qname.c, DNSTypeName(qptr->qtype),
- qptr->InterfaceID, &ptr->addr, (qptr->qDNSServer) ? &qptr->qDNSServer->addr : mDNSNULL);
- cr->resrec.rDNSServer = qptr->qDNSServer;
- }
- }
- else
- {
- LogInfo("uDNS_SetupDNSConfig: Cache Record %##s has no Active question, Record's DNSServer Address %#a, Server to be deleted %#a",
- cr->resrec.name, &cr->resrec.rDNSServer->addr, &ptr->addr);
- cr->resrec.rDNSServer = mDNSNULL;
- }
-
- cr->resrec.mortality = Mortality_Mortal;
- PurgeOrReconfirmCacheRecord(m, cr, ptr, mDNStrue);
- }
- }
*p = (*p)->next;
- LogInfo("uDNS_SetupDNSConfig: Deleting server %p %#a:%d (%##s) %d", ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c, NumUnicastDNSServers);
+ LogInfo("uDNS_SetupDNSConfig: Deleting server %p %#a:%d (%##s)", ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c);
mDNSPlatformMemFree(ptr);
}
else
{
- (*p)->flags &= ~DNSServer_FlagNew;
p = &(*p)->next;
}
}
+ LogInfo("uDNS_SetupDNSConfig: CountOfUnicastDNSServers %d", CountOfUnicastDNSServers(m));
// If we now have no DNS servers at all and we used to have some, then immediately purge all unicast cache records (including for LLQs).
// This is important for giving prompt remove events when the user disconnects the Ethernet cable or turns off wireless.
@@ -15217,6 +15191,7 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
// Force anything that needs to get zone data to get that information again
RestartRecordGetZoneData(m);
}
+#endif // !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
SetDynDNSHostNameIfChanged(m, &fqdn);
@@ -15239,7 +15214,7 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
if (m->FQDN.c[0]) mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1); // Set status to 1 to indicate temporary failure
}
- debugf("uDNS_SetupDNSConfig: number of unicast DNS servers %d", NumUnicastDNSServers);
+ debugf("uDNS_SetupDNSConfig: number of unicast DNS servers %d", CountOfUnicastDNSServers(m));
return mStatus_NoError;
}
@@ -15285,19 +15260,21 @@ mDNSexport void mDNS_StartExit(mDNS *const m)
mDNS_Lock(m);
- LogInfo("mDNS_StartExit");
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "mDNS_StartExit");
m->ShutdownTime = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 5);
mDNSCoreBeSleepProxyServer_internal(m, 0, 0, 0, 0, 0);
-#if APPLE_OSX_mDNSResponder
-#if !NO_WCF
- CHECK_WCF_FUNCTION(WCFConnectionDealloc)
+#if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
+ if (WCFConnectionDealloc)
{
- if (m->WCF) WCFConnectionDealloc((WCFConnection *)m->WCF);
+ if (m->WCF)
+ {
+ WCFConnectionDealloc(m->WCF);
+ m->WCF = mDNSNULL;
+ }
}
#endif
-#endif
#ifndef UNICAST_DISABLED
{
@@ -15320,7 +15297,7 @@ mDNSexport void mDNS_StartExit(mDNS *const m)
}
#endif
- DeadvertiseAllInterfaceRecords(m);
+ DeadvertiseAllInterfaceRecords(m, kDeadvertiseFlag_All);
// Shut down all our active NAT Traversals
while (m->NATTraversals)
@@ -15344,15 +15321,18 @@ mDNSexport void mDNS_StartExit(mDNS *const m)
// Make sure there are nothing but deregistering records remaining in the list
if (m->CurrentRecord)
- LogMsg("mDNS_StartExit: ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "mDNS_StartExit: ERROR m->CurrentRecord already set " PRI_S, ARDisplayString(m, m->CurrentRecord));
+ }
// We're in the process of shutting down, so queries, etc. are no longer available.
// Consequently, determining certain information, e.g. the uDNS update server's IP
// address, will not be possible. The records on the main list are more likely to
// already contain such information, so we deregister the duplicate records first.
- LogInfo("mDNS_StartExit: Deregistering duplicate resource records");
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "mDNS_StartExit: Deregistering duplicate resource records");
DeregLoop(m, m->DuplicateRecords);
- LogInfo("mDNS_StartExit: Deregistering resource records");
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "mDNS_StartExit: Deregistering resource records");
DeregLoop(m, m->ResourceRecords);
// If we scheduled a response to send goodbye packets, we set NextScheduledResponse to now. Normally when deregistering records,
@@ -15363,18 +15343,28 @@ mDNSexport void mDNS_StartExit(mDNS *const m)
m->SuppressSending = 0;
}
- if (m->ResourceRecords) LogInfo("mDNS_StartExit: Sending final record deregistrations");
- else LogInfo("mDNS_StartExit: No deregistering records remain");
+ if (m->ResourceRecords)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "mDNS_StartExit: Sending final record deregistrations");
+ }
+ else
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "mDNS_StartExit: No deregistering records remain");
+ }
for (rr = m->DuplicateRecords; rr; rr = rr->next)
- LogMsg("mDNS_StartExit: Should not still have Duplicate Records remaining: %02X %s", rr->resrec.RecordType, ARDisplayString(m, rr));
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "mDNS_StartExit: Should not still have Duplicate Records remaining: %02X " PRI_S,
+ rr->resrec.RecordType, ARDisplayString(m, rr));
+ }
// If any deregistering records remain, send their deregistration announcements before we exit
if (m->mDNSPlatformStatus != mStatus_NoError) DiscardDeregistrations(m);
mDNS_Unlock(m);
- LogInfo("mDNS_StartExit: done");
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "mDNS_StartExit: done");
}
mDNSexport void mDNS_FinalExit(mDNS *const m)
@@ -15384,7 +15374,7 @@ mDNSexport void mDNS_FinalExit(mDNS *const m)
mDNSu32 slot;
AuthRecord *rr;
- LogInfo("mDNS_FinalExit: mDNSPlatformClose");
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "mDNS_FinalExit: mDNSPlatformClose");
mDNSPlatformClose(m);
for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
@@ -15410,7 +15400,11 @@ mDNSexport void mDNS_FinalExit(mDNS *const m)
for (rr = m->ResourceRecords; rr; rr = rr->next)
LogMsg("mDNS_FinalExit failed to send goodbye for: %p %02X %s", rr, rr->resrec.RecordType, ARDisplayString(m, rr));
- LogInfo("mDNS_FinalExit: done");
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+ uninit_trust_anchors();
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "mDNS_FinalExit: done");
}
#ifdef UNIT_TEST
diff --git a/usr/src/contrib/mDNSResponder/mDNSCore/mDNSDebug.h b/usr/src/contrib/mDNSResponder/mDNSCore/mDNSDebug.h
index 03ed8107fb..e3e453f25a 100755
--- a/usr/src/contrib/mDNSResponder/mDNSCore/mDNSDebug.h
+++ b/usr/src/contrib/mDNSResponder/mDNSCore/mDNSDebug.h
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2018 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2002-2019 Apple Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +17,12 @@
#ifndef __mDNSDebug_h
#define __mDNSDebug_h
+#include "mDNSFeatures.h"
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+#include <os/log.h>
+#endif
+
// Set MDNS_DEBUGMSGS to 0 to optimize debugf() calls out of the compiled code
// Set MDNS_DEBUGMSGS to 1 to generate normal debugging messages
// Set MDNS_DEBUGMSGS to 2 to generate verbose debugging messages
@@ -36,21 +41,61 @@
// warning: double format, pointer arg (arg 2) (for %.4a, %.16a, %#a -- IP address formats)
#define MDNS_CHECK_PRINTF_STYLE_FUNCTIONS 0
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+typedef os_log_t mDNSLogCategory_t;
+
+typedef os_log_type_t mDNSLogLevel_t;
+#define MDNS_LOG_FAULT OS_LOG_TYPE_FAULT
+#define MDNS_LOG_ERROR OS_LOG_TYPE_ERROR
+#define MDNS_LOG_WARNING OS_LOG_TYPE_DEFAULT
+#define MDNS_LOG_DEFAULT OS_LOG_TYPE_DEFAULT
+#define MDNS_LOG_INFO OS_LOG_TYPE_DEFAULT
+#define MDNS_LOG_DEBUG OS_LOG_TYPE_DEBUG
+#else
+typedef const char * mDNSLogCategory_t;
typedef enum
{
- MDNS_LOG_MSG,
- MDNS_LOG_OPERATION,
- MDNS_LOG_SPS,
- MDNS_LOG_INFO,
- MDNS_LOG_DEBUG,
+ MDNS_LOG_FAULT = 1,
+ MDNS_LOG_ERROR = 2,
+ MDNS_LOG_WARNING = 3,
+ MDNS_LOG_DEFAULT = 4,
+ MDNS_LOG_INFO = 5,
+ MDNS_LOG_DEBUG = 6
} mDNSLogLevel_t;
+#endif
-// Set this symbol to 1 to answer remote queries for our Address, reverse mapping PTR, and HINFO records
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+ extern os_log_t mDNSLogCategory_Default;
+ extern os_log_t mDNSLogCategory_mDNS;
+ extern os_log_t mDNSLogCategory_uDNS;
+ extern os_log_t mDNSLogCategory_SPS;
+ extern os_log_t mDNSLogCategory_XPC;
+ extern os_log_t mDNSLogCategory_Analytics;
+ extern os_log_t mDNSLogCategory_DNSSEC;
+
+ #define MDNS_LOG_CATEGORY_DEFINITION(NAME) mDNSLogCategory_ ## NAME
+#else
+ #define MDNS_LOG_CATEGORY_DEFINITION(NAME) # NAME
+#endif
+
+#define MDNS_LOG_CATEGORY_DEFAULT MDNS_LOG_CATEGORY_DEFINITION(Default)
+#define MDNS_LOG_CATEGORY_MDNS MDNS_LOG_CATEGORY_DEFINITION(mDNS)
+#define MDNS_LOG_CATEGORY_UDNS MDNS_LOG_CATEGORY_DEFINITION(uDNS)
+#define MDNS_LOG_CATEGORY_SPS MDNS_LOG_CATEGORY_DEFINITION(SPS)
+#define MDNS_LOG_CATEGORY_XPC MDNS_LOG_CATEGORY_DEFINITION(XPC)
+#define MDNS_LOG_CATEGORY_ANALYTICS MDNS_LOG_CATEGORY_DEFINITION(Analytics)
+#define MDNS_LOG_CATEGORY_DNSSEC MDNS_LOG_CATEGORY_DEFINITION(DNSSEC)
+
+// Set this symbol to 1 to answer remote queries for our Address, and reverse mapping PTR
#define ANSWER_REMOTE_HOSTNAME_QUERIES 0
// Set this symbol to 1 to do extra debug checks on malloc() and free()
// Set this symbol to 2 to write a log message for every malloc() and free()
-//#define MACOSX_MDNS_MALLOC_DEBUGGING 1
+// #define MDNS_MALLOC_DEBUGGING 1
+
+#if (MDNS_MALLOC_DEBUGGING > 0) && defined(WIN32)
+#error "Malloc debugging does not yet work on Windows"
+#endif
//#define ForceAlerts 1
//#define LogTimeStamps 1
@@ -94,21 +139,27 @@ extern "C" {
#if (MDNS_HAS_VA_ARG_MACROS)
#if (MDNS_C99_VA_ARGS)
- #define debug_noop(... ) ((void)0)
- #define LogMsg(... ) LogMsgWithLevel(MDNS_LOG_MSG, __VA_ARGS__)
- #define LogOperation(... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_OPERATION, __VA_ARGS__);} while (0)
- #define LogSPS(... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_SPS, __VA_ARGS__);} while (0)
- #define LogInfo(... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_INFO, __VA_ARGS__);} while (0)
- #define LogDebug(... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_DEBUG, __VA_ARGS__);} while (0)
+ #define MDNS_LOG_DEFINITION(LEVEL, ...) \
+ do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_CATEGORY_DEFAULT, LEVEL, __VA_ARGS__); } while (0)
+
+ #define debug_noop(...) do {} while(0)
+ #define LogMsg(...) LogMsgWithLevel(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, __VA_ARGS__)
+ #define LogOperation(...) MDNS_LOG_DEFINITION(MDNS_LOG_INFO, __VA_ARGS__)
+ #define LogSPS(...) MDNS_LOG_DEFINITION(MDNS_LOG_INFO, __VA_ARGS__)
+ #define LogInfo(...) MDNS_LOG_DEFINITION(MDNS_LOG_INFO, __VA_ARGS__)
+ #define LogDebug(...) MDNS_LOG_DEFINITION(MDNS_LOG_DEBUG, __VA_ARGS__)
#elif (MDNS_GNU_VA_ARGS)
- #define debug_noop( ARGS... ) ((void)0)
- #define LogMsg( ARGS... ) LogMsgWithLevel(MDNS_LOG_MSG, ARGS)
- #define LogOperation( ARGS... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_OPERATION, ARGS);} while (0)
- #define LogSPS( ARGS... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_SPS, ARGS);} while (0)
- #define LogInfo( ARGS... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_INFO, ARGS);} while (0)
- #define LogDebug( ARGS... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_DEBUG, ARGS);} while (0)
+ #define MDNS_LOG_DEFINITION(LEVEL, ARGS...) \
+ do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_CATEGORY_DEFAULT, LEVEL, ARGS); } while (0)
+
+ #define debug_noop(ARGS...) do {} while (0)
+ #define LogMsg(ARGS... ) LogMsgWithLevel(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, ARGS)
+ #define LogOperation(ARGS...) MDNS_LOG_DEFINITION(MDNS_LOG_INFO, ARGS)
+ #define LogSPS(ARGS...) MDNS_LOG_DEFINITION(MDNS_LOG_INFO, ARGS)
+ #define LogInfo(ARGS...) MDNS_LOG_DEFINITION(MDNS_LOG_INFO, ARGS)
+ #define LogDebug(ARGS...) MDNS_LOG_DEFINITION(MDNS_LOG_DEBUG, ARGS)
#else
- #error Unknown variadic macros
+ #error "Unknown variadic macros"
#endif
#else
// If your platform does not support variadic macros, you need to define the following variadic functions.
@@ -126,6 +177,7 @@ extern void LogInfo_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,
extern void LogDebug_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
#endif
+
#if MDNS_DEBUGMSGS
#define debugf debugf_
extern void debugf_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
@@ -147,7 +199,7 @@ extern int mDNS_McastTracingEnabled;
extern int mDNS_DebugMode; // If non-zero, LogMsg() writes to stderr instead of syslog
extern const char ProgramName[];
-extern void LogMsgWithLevel(mDNSLogLevel_t logLevel, const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(2,3);
+extern void LogMsgWithLevel(mDNSLogCategory_t category, mDNSLogLevel_t level, const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(3,4);
// LogMsgNoIdent needs to be fixed so that it logs without the ident prefix like it used to
// (or completely overhauled to use the new "log to a separate file" facility)
#define LogMsgNoIdent LogMsg
@@ -158,19 +210,208 @@ extern void LogFatalError(const char *format, ...);
#define LogFatalError LogMsg
#endif
-#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1
-extern void *mallocL(char *msg, unsigned int size);
-extern void freeL(char *msg, void *x);
-extern void uds_validatelists(void);
-extern void udns_validatelists(void *const v);
+#if MDNS_MALLOC_DEBUGGING >= 1
+extern void *mallocL(const char *msg, mDNSu32 size);
+extern void *callocL(const char *msg, mDNSu32 size);
+extern void freeL(const char *msg, void *x);
+#if APPLE_OSX_mDNSResponder
extern void LogMemCorruption(const char *format, ...);
#else
-#define mallocL(X,Y) malloc(Y)
-#define freeL(X,Y) free(Y)
+#define LogMemCorruption LogMsg
+#endif
+#else
+#define mallocL(MSG, SIZE) malloc(SIZE)
+#define callocL(MSG, SIZE) calloc(1, SIZE)
+#define freeL(MSG, PTR) free(PTR)
#endif
#ifdef __cplusplus
}
#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+/** @brief Write a log message to system's log storage(memory or disk).
+ *
+ * On Apple platform, os_log() will be called to log a message.
+ *
+ * @param CATEGORY A custom log object previously created by the os_log_create function, and such an object is
+ * used to specify "subsystem" and "category". For mDNSResponder, the subsystem should always
+ * be set to "com.apple.mDNSResponder"; and the category is used for categorization and
+ * filtering of related log messages within the subsystem’s settings. We have 4 categories that
+ * are pre-defined: MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_CATEGORY_UDNS,
+ * MDNS_LOG_CATEGORY_SPS. If these categories are not enough, use os_log_create to create more.
+ *
+ * @param LEVEL The log level that determines the importance of the message. The levels are, in order of
+ * decreasing importance:
+ * MDNS_LOG_FAULT Fault-level messages are intended for capturing system-level errors
+ * that are critical to the system. They are always saved in the data store.
+ * MDNS_LOG_ERROR Error-level messages are intended for reporting process-level errors
+ * that are unexpected and incorrect during the normal operation. They
+ * are always saved in the data store.
+ * MDNS_LOG_WARNING Warning-level messages are intended for capturing unexpected and
+ * possible incorrect behavior that might be used later to root cause
+ * an error or fault. They are are initially stored in memory buffers
+ * and then moved to a data store.
+ * MDNS_LOG_DEFAULT Default-level messages are intended for reporting things that might
+ * result a failure. They are are initially stored in memory buffers
+ * and then moved to a data store.
+ * MDNS_LOG_INFO Info-level messages are intended for capturing information that may
+ * be helpful, but isn’t essential, for troubleshooting errors. They
+ * are initially stored in memory buffers, but will only be moved into
+ * data store when faults and, optionally, errors occur.
+ * MDNS_LOG_DEBUG Debug-level messages are intended for information that may be useful
+ * during development or while troubleshooting a specific problem, Debug
+ * logging should not be used in shipping software. They are only
+ * captured in memory when debug logging is enabled through a
+ * configuration change.
+ *
+ * @param FORMAT A constant string or format string that produces a human-readable log message. The format
+ * string follows the IEEE printf specification, besides the following customized format specifiers:
+ * %{mdnsresponder:domain_name}.*P the pointer to a DNS lable sequence
+ * %{mdnsresponder:ip_addr}.20P the pointer to a mDNSAddr variable
+ * %{network:in_addr}.4P the pointer to a mDNSv4Addr variable
+ * %{network:in6_addr}.16P the pointer to a mDNSv6Addr variable
+ * %{mdnsresponder:mac_addr}.6P the pointer to a 6-byte-length MAC address
+ *
+ * @param ... The parameter list that will be formated by the format string. Note that if the customized
+ * format specifiers are used and the data length is not specified in the format string, the
+ * size should be listed before the pointer to the data, for example:
+ * "%{mdnsresponder:domain_name}.*P", (name ? (int)DomainNameLength((const domainname *)name) : 0), <the pointer to a DNS label sequence>
+ *
+ */
+ #define LogRedact(CATEGORY, LEVEL, FORMAT, ...) os_log_with_type(CATEGORY, LEVEL, FORMAT, ## __VA_ARGS__)
+#else
+ #if (MDNS_HAS_VA_ARG_MACROS)
+ #if (MDNS_C99_VA_ARGS)
+ #define LogRedact(CATEGORY, LEVEL, ...) \
+ do { if (mDNS_LoggingEnabled) LogMsgWithLevel(CATEGORY, LEVEL, __VA_ARGS__); } while (0)
+ #elif (MDNS_GNU_VA_ARGS)
+ #define LogRedact(CATEGORY, LEVEL, ARGS...) \
+ do { if (mDNS_LoggingEnabled) LogMsgWithLevel(CATEGORY, LEVEL, ARGS); } while (0)
+ #else
+ #error "Unknown variadic macros"
+ #endif
+ #else
+ #define LogRedact (mDNS_LoggingEnabled == 0) ? ((void)0) : LogRedact_
+ extern void LogRedact_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
+ #endif
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+
+// The followings are the customized log specifier defined in os_log. For compatibility, we have to define it when it is
+// not on the Apple platform, for example, the Posix platform. The keyword "public" or "private" is used to control whether
+// the content would be redacted when the redaction is turned on: "public" means the content will always be printed;
+// "private" means the content will be printed as <mask.hash: '<The hashed string from binary data>'> if the redaction is turned on,
+// only when the redaction is turned off, the content will be printed as what it should be. Note that the hash performed
+// to the data is a salted hashing transformation, and the salt is generated randomly on a per-process basis, meaning
+// that hashes cannot be correlated across processes or devices.
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+ #define PUB_S "%{public}s"
+ #define PRI_S "%{private, mask.hash}s"
+#else
+ #define PUB_S "%s"
+ #define PRI_S PUB_S
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+ #define PUB_DM_NAME "%{public, mdnsresponder:domain_name}.*P"
+ #define PRI_DM_NAME "%{private, mask.hash, mdnsresponder:domain_name}.*P"
+ // When DM_NAME_PARAM is used, the file where the function is defined must include DNSEmbeddedAPI.h
+ #define DM_NAME_PARAM(name) ((name) ? ((int)DomainNameLength((name))) : 0), (name)
+#else
+ #define PUB_DM_NAME "%##s"
+ #define PRI_DM_NAME PUB_DM_NAME
+ #define DM_NAME_PARAM(name) (name)
#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+ #define PUB_IP_ADDR "%{public, mdnsresponder:ip_addr}.20P"
+ #define PRI_IP_ADDR "%{private, mask.hash, mdnsresponder:ip_addr}.20P"
+
+ #define PUB_IPv4_ADDR "%{public, network:in_addr}.4P"
+ #define PRI_IPv4_ADDR "%{private, mask.hash, network:in_addr}.4P"
+
+ #define PUB_IPv6_ADDR "%{public, network:in6_addr}.16P"
+ #define PRI_IPv6_ADDR "%{private, mask.hash, network:in6_addr}.16P"
+#else
+ #define PUB_IP_ADDR "%#a"
+ #define PRI_IP_ADDR PUB_IP_ADDR
+
+ #define PUB_IPv4_ADDR "%.4a"
+ #define PRI_IPv4_ADDR PUB_IPv4_ADDR
+
+ #define PUB_IPv6_ADDR "%.16a"
+ #define PRI_IPv6_ADDR PUB_IPv6_ADDR
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+ #define PUB_MAC_ADDR "%{public, mdnsresponder:mac_addr}.6P"
+ #define PRI_MAC_ADDR "%{private, mask.hash, mdnsresponder:mac_addr}.6P"
+#else
+ #define PUB_MAC_ADDR "%.6a"
+ #define PRI_MAC_ADDR PUB_MAC_ADDR
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+ #define PUB_DNSKEY "%{public, mdns:rd.dnskey}.*P"
+ #define PRI_DNSKEY "%{private, mask.hash, mdns:rd.dnskey}.*P"
+ #define DNSKEY_PARAM(rdata, rdata_length) (rdata_length), (rdata)
+#else
+ #define PUB_DNSKEY "%p"
+ #define PRI_DNSKEY PUB_DNSKEY
+ #define DNSKEY_PARAM(rdata, rdata_length) (rdata)
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+ #define PUB_DS "%{public, mdns:rd.ds}.*P"
+ #define PRI_DS "%{private, mask.hash, mdns:rd.ds}.*P"
+ #define DS_PARAM(rdata, rdata_length) (rdata_length), (rdata)
+#else
+ #define PUB_DS "%p"
+ #define PRI_DS PUB_DS
+ #define DS_PARAM(rdata, rdata_length) (rdata)
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+ #define PUB_NSEC "%{public, mdns:rd.nsec}.*P"
+ #define PRI_NSEC "%{private, mask.hash, mdns:rd.nsec}.*P"
+ #define NSEC_PARAM(rdata, rdata_length) (rdata_length), (rdata)
+#else
+ #define PUB_NSEC "%p"
+ #define PRI_NSEC PUB_NSEC
+ #define NSEC_PARAM(rdata, rdata_length) (rdata)
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+ #define PUB_NSEC3 "%{public, mdns:rd.nsec3}.*P"
+ #define PRI_NSEC3 "%{private, mask.hash, mdns:rd.nsec3}.*P"
+ #define NSEC3_PARAM(rdata, rdata_length) (rdata_length), (rdata)
+#else
+ #define PUB_NSEC3 "%p"
+ #define PRI_NSEC3 PUB_NSEC3
+ #define NSEC3_PARAM(rdata, rdata_length) (rdata)
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+ #define PUB_RRSIG "%{public, mdns:rd.rrsig}.*P"
+ #define PRI_RRSIG "%{private, mask.hash, mdns:rd.rrsig}.*P"
+ #define RRSIG_PARAM(rdata, rdata_length) (rdata_length), (rdata)
+#else
+ #define PUB_RRSIG "%p"
+ #define PRI_RRSIG PUB_RRSIG
+ #define RRSIG_PARAM(rdata, rdata_length) (rdata)
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+ #define PUB_SVCB "%{public, mdns:rd.svcb}.*P"
+ #define PRI_SVCB "%{private, mask.hash, mdns:rd.svcb}.*P"
+ #define SVCB_PARAM(rdata, rdata_length) (rdata_length), (rdata)
+#else
+ #define PUB_SVCB "%p"
+ #define PRI_SVCB PUB_SVCB
+ #define SVCB_PARAM(rdata, rdata_length) (rdata)
+#endif
+
+extern void LogToFD(int fd, const char *format, ...);
+
+#endif // __mDNSDebug_h
diff --git a/usr/src/contrib/mDNSResponder/mDNSCore/mDNSEmbeddedAPI.h b/usr/src/contrib/mDNSResponder/mDNSCore/mDNSEmbeddedAPI.h
index 772664fe02..321a926f20 100755
--- a/usr/src/contrib/mDNSResponder/mDNSCore/mDNSEmbeddedAPI.h
+++ b/usr/src/contrib/mDNSResponder/mDNSCore/mDNSEmbeddedAPI.h
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2018 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2002-2020 Apple Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -67,15 +66,12 @@
#include <stdarg.h> // stdarg.h is required for for va_list support for the mDNS_vsnprintf declaration
#endif
-#include "mDNSDebug.h"
#if APPLE_OSX_mDNSResponder
#include <uuid/uuid.h>
-#include <TargetConditionals.h>
#endif
-#ifdef __cplusplus
-extern "C" {
-#endif
+#include "mDNSFeatures.h"
+#include "mDNSDebug.h"
// ***************************************************************************
// Feature removal compile options & limited resource targets
@@ -84,13 +80,19 @@ extern "C" {
// memory footprint for use in embedded systems with limited resources.
// UNICAST_DISABLED - disables unicast DNS functionality, including Wide Area Bonjour
-// ANONYMOUS_DISABLED - disables anonymous functionality
-// DNSSEC_DISABLED - disables DNSSEC functionality
// SPC_DISABLED - disables Bonjour Sleep Proxy client
// IDLESLEEPCONTROL_DISABLED - disables sleep control for Bonjour Sleep Proxy clients
// In order to disable the above features pass the option to your compiler, e.g. -D UNICAST_DISABLED
+#if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
+#include <WebFilterDNS/WebFilterDNS.h>
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+#include "dnssec_v2_embedded.h"
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+
// Additionally, the LIMITED_RESOURCES_TARGET compile option will reduce the maximum DNS message sizes.
#ifdef LIMITED_RESOURCES_TARGET
@@ -101,8 +103,12 @@ extern "C" {
#define MaximumRDSize 264
#endif
-#if !defined(MDNSRESPONDER_BTMM_SUPPORT)
-#define MDNSRESPONDER_BTMM_SUPPORT 0
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+#include "mdns_private.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
#endif
// ***************************************************************************
@@ -150,6 +156,20 @@ extern "C" {
#endif
#endif
+#ifndef fallthrough
+ #if __clang__
+ #if __has_c_attribute(fallthrough)
+ #define fallthrough() [[fallthrough]]
+ #else
+ #define fallthrough()
+ #endif
+ #elif __GNUC__
+ #define fallthrough() __attribute__((fallthrough))
+ #else
+ #define fallthrough()
+ #endif // __GNUC__
+#endif // fallthrough
+
// ***************************************************************************
#if 0
#pragma mark - DNS Resource Record class and type constants
@@ -226,6 +246,9 @@ typedef enum // From RFC 1035
kDNSType_HIP = 55, // 55 Host Identity Protocol
+ kDNSType_SVCB = 64, // 64 Service Binding
+ kDNSType_HTTPS, // 65 HTTPS Service Binding
+
kDNSType_SPF = 99, // 99 Sender Policy Framework for E-Mail
kDNSType_UINFO, // 100 IANA-Reserved
kDNSType_UID, // 101 IANA-Reserved
@@ -238,7 +261,7 @@ typedef enum // From RFC 1035
kDNSType_AXFR, // 252 Transfer zone of authority
kDNSType_MAILB, // 253 Transfer mailbox records
kDNSType_MAILA, // 254 Transfer mail agent records
- kDNSQType_ANY // Not a DNS type, but a DNS query type, meaning "all types"
+ kDNSQType_ANY // Not a DNS type, but a DNS query type, meaning "all types"
} DNS_TypeValues;
// ***************************************************************************
@@ -269,7 +292,12 @@ typedef unsigned int mDNSu32;
// To enforce useful type checking, we make mDNSInterfaceID be a pointer to a dummy struct
// This way, mDNSInterfaceIDs can be assigned, and compared with each other, but not with other types
// Declaring the type to be the typical generic "void *" would lack this type checking
-typedef struct mDNSInterfaceID_dummystruct { void *dummy; } *mDNSInterfaceID;
+typedef const struct mDNSInterfaceID_dummystruct { void *dummy; } *mDNSInterfaceID;
+
+// Use when printing interface IDs; the interface ID is actually a pointer, but we're only using
+// the pointer as a unique identifier, and in special cases it's actually a small number. So there's
+// little point in printing all 64 bits--the upper 32 bits in particular will not add information.
+#define IIDPrintable(x) ((uint32_t)(uintptr_t)(x))
// These types are for opaque two- and four-byte identifiers.
// The "NotAnInteger" fields of the unions allow the value to be conveniently passed around in a
@@ -377,8 +405,12 @@ enum
mStatus_NoRouter = -65566,
mStatus_PollingMode = -65567,
mStatus_Timeout = -65568,
- mStatus_HostUnreachErr = -65569,
- // -65570 to -65786 currently unused; available for allocation
+ mStatus_DefunctConnection = -65569,
+ mStatus_PolicyDenied = -65570,
+ // -65571 to -65785 currently unused; available for allocation
+
+ // udp connection status
+ mStatus_HostUnreachErr = -65786,
// tcp connection status
mStatus_ConnPending = -65787,
@@ -389,10 +421,12 @@ enum
mStatus_GrowCache = -65790,
mStatus_ConfigChanged = -65791,
mStatus_MemFree = -65792 // Last value: 0xFFFE FF00
- // mStatus_MemFree is the last legal mDNS error code, at the end of the range allocated for mDNS
+
+ // mStatus_MemFree is the last legal mDNS error code, at the end of the range allocated for mDNS
};
typedef mDNSs32 mStatus;
+
#define MaxIp 5 // Needs to be consistent with MaxInputIf in dns_services.h
typedef enum { q_stop = 0, q_start } q_state;
@@ -440,13 +474,6 @@ typedef struct { mDNSu8 c[256]; } UTF8str255; // Null-terminated C string
#define kStandardTTL (3600UL * 100 / 80)
#define kHostNameTTL 120UL
-// Some applications want to register their SRV records with a lower ttl so that in case the server
-// using a dynamic port number restarts, the clients will not have stale information for more than
-// 10 seconds
-
-#define kHostNameSmallTTL 10UL
-
-
// Multicast DNS uses announcements (gratuitous responses) to update peer caches.
// This means it is feasible to use relatively larger TTL values than we might otherwise
// use, because we have a cache coherency protocol to keep the peer caches up to date.
@@ -482,6 +509,7 @@ typedef struct ResourceRecord_struct ResourceRecord;
// Structure to abstract away the differences between TCP/SSL sockets, and one for UDP sockets
// The actual definition of these structures appear in the appropriate platform support code
+typedef struct TCPListener_struct TCPListener;
typedef struct TCPSocket_struct TCPSocket;
typedef struct UDPSocket_struct UDPSocket;
@@ -781,133 +809,6 @@ typedef packedstruct
mDNSu32 min; // Nominally the minimum record TTL for this zone, in seconds; also used for negative caching.
} rdataSOA;
-// http://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml
-// Algorithm used for RRSIG, DS and DNS KEY
-#define CRYPTO_RSA_SHA1 0x05
-#define CRYPTO_DSA_NSEC3_SHA1 0x06
-#define CRYPTO_RSA_NSEC3_SHA1 0x07
-#define CRYPTO_RSA_SHA256 0x08
-#define CRYPTO_RSA_SHA512 0x0A
-
-#define CRYPTO_ALG_MAX 0x0B
-
-// alg - same as in RRSIG, DNS KEY or DS.
-// RFC 4034 defines SHA1
-// RFC 4509 defines SHA256
-// Note: NSEC3 also uses 1 for SHA1 and hence we will reuse for now till a new
-// value is assigned.
-//
-#define SHA1_DIGEST_TYPE 1
-#define SHA256_DIGEST_TYPE 2
-#define DIGEST_TYPE_MAX 3
-
-// We need support for base64 and base32 encoding for displaying KEY, NSEC3
-// To make this platform agnostic, we define two types which the platform
-// needs to support
-#define ENC_BASE32 1
-#define ENC_BASE64 2
-#define ENC_ALG_MAX 3
-
-#define DS_FIXED_SIZE 4
-typedef packedstruct
-{
- mDNSu16 keyTag;
- mDNSu8 alg;
- mDNSu8 digestType;
- mDNSu8 *digest;
-} rdataDS;
-
-typedef struct TrustAnchor
-{
- struct TrustAnchor *next;
- int digestLen;
- mDNSu32 validFrom;
- mDNSu32 validUntil;
- domainname zone;
- rdataDS rds;
-} TrustAnchor;
-
-//size of rdataRRSIG excluding signerName and signature (which are variable fields)
-#define RRSIG_FIXED_SIZE 18
-typedef struct
-{
- mDNSu16 typeCovered;
- mDNSu8 alg;
- mDNSu8 labels;
- mDNSu32 origTTL;
- mDNSu32 sigExpireTime;
- mDNSu32 sigInceptTime;
- mDNSu16 keyTag;
- mDNSu8 signerName[1]; // signerName is a dynamically-sized array
- // mDNSu8 *signature
-} rdataRRSig;
-
-// RFC 4034: For DNS Key RR
-// flags - the valid value for DNSSEC is 256 (Zone signing key - ZSK) and 257 (Secure Entry Point) which also
-// includes the ZSK bit
-//
-#define DNSKEY_ZONE_SIGN_KEY 0x100
-#define DNSKEY_SECURE_ENTRY_POINT 0x101
-
-// proto - the only valid value for protocol is 3 (See RFC 4034)
-#define DNSKEY_VALID_PROTO_VALUE 0x003
-
-// alg - The only mandatory algorithm that we support is RSA/SHA-1
-// DNSSEC_RSA_SHA1_ALG
-
-#define DNSKEY_FIXED_SIZE 4
-typedef packedstruct
-{
- mDNSu16 flags;
- mDNSu8 proto;
- mDNSu8 alg;
- mDNSu8 *data;
-} rdataDNSKey;
-
-#define NSEC3_FIXED_SIZE 5
-#define NSEC3_FLAGS_OPTOUT 1
-#define NSEC3_MAX_ITERATIONS 2500
-typedef packedstruct
-{
- mDNSu8 alg;
- mDNSu8 flags;
- mDNSu16 iterations;
- mDNSu8 saltLength;
- mDNSu8 *salt;
- // hashLength, nxt, bitmap
-} rdataNSEC3;
-
-// In the multicast usage of NSEC3, we know the actual size of RData
-// 4 bytes : HashAlg, Flags,Iterations
-// 5 bytes : Salt Length 1 byte, Salt 4 bytes
-// 21 bytes : HashLength 1 byte, Hash 20 bytes
-// 34 bytes : Window number, Bitmap length, Type bit map to include the first 256 types
-#define MCAST_NSEC3_RDLENGTH (4 + 5 + 21 + 34)
-#define SHA1_HASH_LENGTH 20
-
-// Base32 encoding takes 5 bytes of the input and encodes as 8 bytes of output.
-// For example, SHA-1 hash of 20 bytes will be encoded as 20/5 * 8 = 32 base32
-// bytes. For a max domain name size of 255 bytes of base32 encoding : (255/8)*5
-// is the max hash length possible.
-#define NSEC3_MAX_HASH_LEN 155
-// In NSEC3, the names are hashed and stored in the first label and hence cannot exceed label
-// size.
-#define NSEC3_MAX_B32_LEN MAX_DOMAIN_LABEL
-
-// We define it here instead of dnssec.h so that these values can be used
-// in files without bringing in all of dnssec.h unnecessarily.
-typedef enum
-{
- DNSSEC_Secure = 1, // Securely validated and has a chain up to the trust anchor
- DNSSEC_Insecure, // Cannot build a chain up to the trust anchor
- DNSSEC_Indeterminate, // Not used currently
- DNSSEC_Bogus, // failed to validate signatures
- DNSSEC_NoResponse // No DNSSEC records to start with
-} DNSSECStatus;
-
-#define DNSSECRecordType(rrtype) (((rrtype) == kDNSType_RRSIG) || ((rrtype) == kDNSType_NSEC) || ((rrtype) == kDNSType_DNSKEY) || ((rrtype) == kDNSType_DS) || \
- ((rrtype) == kDNSType_NSEC3))
-
typedef enum
{
platform_OSX = 1, // OSX Platform
@@ -1056,9 +957,6 @@ typedef union
mDNSv6Addr ipv6; // For 'AAAA' record
rdataSRV srv;
rdataOPT opt[2]; // For EDNS0 OPT record; RDataBody may contain multiple variable-length rdataOPT objects packed together
- rdataDS ds;
- rdataDNSKey key;
- rdataRRSig rrsig;
} RDataBody2;
typedef struct
@@ -1321,15 +1219,6 @@ struct NATTraversalInfo_struct
enum
{
- DNSServer_FlagDelete = 0x1,
- DNSServer_FlagNew = 0x2,
-#if APPLE_OSX_mDNSResponder
- DNSServer_FlagUnreachable = 0x4,
-#endif
-};
-
-enum
-{
McastResolver_FlagDelete = 1,
McastResolver_FlagNew = 2
};
@@ -1350,58 +1239,51 @@ enum {
};
typedef mDNSu8 MortalityState;
-// scoped values for DNSServer matching
-enum
+// ScopeType values for DNSServer matching
+typedef enum
{
kScopeNone = 0, // DNS server used by unscoped questions
kScopeInterfaceID = 1, // Scoped DNS server used only by scoped questions
- kScopeServiceID = 2, // Service specific DNS server used only by questions
+ kScopeServiceID = 2 // Service specific DNS server used only by questions
// have a matching serviceID
- kScopesMaxCount = 3 // Max count for scopes enum
-};
+} ScopeType;
+
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+typedef mDNSu32 DNSServerFlags;
+#define DNSServerFlag_Delete (1U << 0)
+#if MDNSRESPONDER_SUPPORTS(APPLE, SYMPTOMS)
+#define DNSServerFlag_Unreachable (1U << 1)
+#endif
-// Note: DNSSECAware is set if we are able to get a valid response to
-// a DNSSEC question. In some cases it is possible that the proxy
-// strips the EDNS0 option and we just get a plain response with no
-// signatures. But we still mark DNSSECAware in that case. As DNSSECAware
-// is only used to determine whether DNSSEC_VALIDATION_SECURE_OPTIONAL
-// should be turned off or not, it is sufficient that we are getting
-// responses back.
typedef struct DNSServer
{
struct DNSServer *next;
mDNSInterfaceID interface; // DNS requests should be sent on this interface
- mDNSs32 serviceID;
- mDNSAddr addr;
- mDNSIPPort port;
- mDNSu32 flags; // Set when we're planning to delete this from the list
- domainname domain; // name->server matching for "split dns"
+ mDNSs32 serviceID; // ServiceID from DNS configuration.
+ mDNSAddr addr; // DNS server's IP address.
+ DNSServerFlags flags; // Set when we're planning to delete this from the list.
mDNSs32 penaltyTime; // amount of time this server is penalized
- mDNSu32 scoped; // See the scoped enum above
+ ScopeType scopeType; // See the ScopeType enum above
mDNSu32 timeout; // timeout value for questions
- mDNSu16 resGroupID; // ID of the resolver group that contains this DNSServer
- mDNSu8 retransDO; // Total Retransmissions for queries sent with DO option
- mDNSBool cellIntf; // Resolver from Cellular Interface?
- mDNSBool req_A; // If set, send v4 query (DNSConfig allows A queries)
- mDNSBool req_AAAA; // If set, send v6 query (DNSConfig allows AAAA queries)
- mDNSBool req_DO; // If set, okay to send DNSSEC queries (EDNS DO bit is supported)
- mDNSBool DNSSECAware; // Set if we are able to receive a response to a request sent with DO option.
+ mDNSu32 resGroupID; // ID of the resolver group that contains this DNSServer
+ mDNSIPPort port; // DNS server's port number.
+ mDNSBool usableA; // True if A query results are usable over the interface, i.e., interface has IPv4.
+ mDNSBool usableAAAA; // True if AAAA query results are usable over the interface, i.e., interface has IPv6.
+ mDNSBool isCell; // True if the interface to this server is cellular.
mDNSBool isExpensive; // True if the interface to this server is expensive.
- mDNSBool isCLAT46; // True if the interface to this server is CLAT46.
+ mDNSBool isConstrained; // True if the interface to this server is constrained.
+ mDNSBool isCLAT46; // True if the interface to this server supports CLAT46.
+ domainname domain; // name->server matching for "split dns"
} DNSServer;
+#endif
-typedef struct
-{
- mDNSu8 *AnonData;
- int AnonDataLen;
- mDNSu32 salt;
- ResourceRecord *nsec3RR;
- mDNSInterfaceID SendNow; // The interface ID that this record should be sent on
-} AnonymousInfo;
+#define kNegativeRecordType_Unspecified 0 // Initializer of ResourceRecord didn't specify why the record is negative.
+#define kNegativeRecordType_NoData 1 // The record's name exists, but there are no records of this type.
struct ResourceRecord_struct
{
mDNSu8 RecordType; // See kDNSRecordTypes enum.
+ mDNSu8 negativeRecordType; // If RecordType is kDNSRecordTypePacketNegative, specifies type of negative record.
MortalityState mortality; // Mortality of this resource record (See MortalityState enum)
mDNSu16 rrtype; // See DNS_TypeValues enum.
mDNSu16 rrclass; // See DNS_ClassValues enum.
@@ -1423,8 +1305,21 @@ struct ResourceRecord_struct
// that are interface-specific (e.g. address records, especially linklocal addresses)
const domainname *name;
RData *rdata; // Pointer to storage for this rdata
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ mdns_dns_service_t dnsservice;
+ mdns_resolver_type_t protocol;
+#else
DNSServer *rDNSServer; // Unicast DNS server authoritative for this entry; null for multicast
- AnonymousInfo *AnonInfo; // Anonymous Information
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+ dnssec_result_t dnssec_result; // DNSSEC validation result of the current resource record.
+ // For all DNSSEC-disabled queries, the result would always be dnssec_indeterminate.
+ // For DNSSEC-enabled queries, the result would be dnssec_indeterminate,
+ // dnssec_secure, dnssec_insecure, or dnssec_bogus, see
+ // <https://tools.ietf.org/html/rfc4033#section-5> for the detailed meaning of
+ // each state.
+#endif
};
@@ -1495,9 +1390,12 @@ typedef enum
AuthRecordAnyIncludeAWDL, // registered for *Any, including AWDL interface
AuthRecordAnyIncludeAWDLandP2P, // registered for *Any, including AWDL and P2P interfaces
AuthRecordLocalOnly,
- AuthRecordP2P // discovered over D2D/P2P framework
+ AuthRecordP2P, // discovered over D2D/P2P framework
} AuthRecType;
+#define AuthRecordIncludesAWDL(AR) \
+ (((AR)->ARType == AuthRecordAnyIncludeAWDL) || ((AR)->ARType == AuthRecordAnyIncludeAWDLandP2P))
+
typedef enum
{
AuthFlagsWakeOnly = 0x1 // WakeOnly service
@@ -1534,6 +1432,8 @@ struct AuthRecord_struct
mDNSs32 KATimeExpire; // In platform time units: time to send keepalive packet for the proxy record
// Field Group 3: Transient state for Authoritative Records
+ mDNSs32 ProbingConflictCount; // Number of conflicting records observed during probing.
+ mDNSs32 LastConflictPktNum; // Number of the last received packet that caused a probing conflict.
mDNSu8 Acknowledged; // Set if we've given the success callback to the client
mDNSu8 ProbeRestartCount; // Number of times we have restarted probing
mDNSu8 ProbeCount; // Number of probes remaining before this record is valid (kDNSRecordTypeUnique)
@@ -1615,7 +1515,7 @@ struct AuthRecord_struct
// Note: Question_uDNS(Q) is used in *only* one place -- on entry to mDNS_StartQuery_internal, to decide whether to set TargetQID.
// Everywhere else in the code, the determination of whether a question is unicast is made by checking to see if TargetQID is nonzero.
#define AuthRecord_uDNS(R) ((R)->resrec.InterfaceID == mDNSInterface_Any && !(R)->ForceMCast && !IsLocalDomain((R)->resrec.name))
-#define Question_uDNS(Q) ((Q)->InterfaceID == mDNSInterface_Unicast || (Q)->ProxyQuestion || \
+#define Question_uDNS(Q) ((Q)->IsUnicastDotLocal || (Q)->ProxyQuestion || \
((Q)->InterfaceID != mDNSInterface_LocalOnly && (Q)->InterfaceID != mDNSInterface_P2P && (Q)->InterfaceID != mDNSInterface_BLE && !(Q)->ForceMCast && !IsLocalDomain(&(Q)->qname)))
// AuthRecordLocalOnly records are registered using mDNSInterface_LocalOnly and
@@ -1625,13 +1525,6 @@ struct AuthRecord_struct
// All other auth records, not including those defined as RRLocalOnly().
#define RRAny(rr) ((rr)->ARType == AuthRecordAny || (rr)->ARType == AuthRecordAnyIncludeP2P || (rr)->ARType == AuthRecordAnyIncludeAWDL || (rr)->ARType == AuthRecordAnyIncludeAWDLandP2P)
-// Question (A or AAAA) that is suppressed currently because IPv4 or IPv6 address
-// is not available locally for A or AAAA question respectively. Also, if the
-// query is disallowed for the "pid" that we are sending on behalf of, suppress it.
-#define QuerySuppressed(Q) (((Q)->SuppressUnusable && (Q)->SuppressQuery) || ((Q)->DisallowPID))
-
-#define PrivateQuery(Q) ((Q)->AuthInfo && (Q)->AuthInfo->AutoTunnel)
-
// Normally we always lookup the cache and /etc/hosts before sending the query on the wire. For single label
// queries (A and AAAA) that are unqualified (indicated by AppendSearchDomains), we want to append search
// domains before we try them as such
@@ -1654,15 +1547,21 @@ struct CacheRecord_struct
mDNSs32 TimeRcvd; // In platform time units
mDNSs32 DelayDelivery; // Set if we want to defer delivery of this answer to local clients
mDNSs32 NextRequiredQuery; // In platform time units
+#if MDNSRESPONDER_SUPPORTS(APPLE, CACHE_ANALYTICS)
+ mDNSs32 LastCachedAnswerTime; // Last time this record was used as an answer from the cache (before a query)
+ // In platform time units
+#else
// Extra four bytes here (on 64bit)
+#endif
DNSQuestion *CRActiveQuestion; // Points to an active question referencing this answer. Can never point to a NewQuestion.
mDNSs32 LastUnansweredTime; // In platform time units; last time we incremented UnansweredQueries
mDNSu8 UnansweredQueries; // Number of times we've issued a query for this record without getting an answer
- mDNSu8 CRDNSSECQuestion; // Set to 1 if this was created in response to a DNSSEC question
mDNSOpaque16 responseFlags; // Second 16 bit in the DNS response
CacheRecord *NextInCFList; // Set if this is in the list of records we just received with the cache flush bit set
- CacheRecord *nsec; // NSEC records needed for non-existence proofs
CacheRecord *soa; // SOA record to return for proxy questions
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+ void *denial_of_existence_records; // denial_of_existence_records_t
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
mDNSAddr sourceAddress; // node from which we received this record
// Size to here is 76 bytes when compiling 32-bit; 104 bytes when compiling 64-bit (now 160 bytes for 64-bit)
@@ -1749,8 +1648,7 @@ struct ServiceRecordSet_struct
ExtraResourceRecord *Extras; // Optional list of extra AuthRecords attached to this service registration
mDNSu32 NumSubTypes;
AuthRecord *SubTypes;
- const mDNSu8 *AnonData;
- mDNSu32 flags; // saved for subsequent calls to mDNS_RegisterService() if records
+ mDNSu32 flags; // saved for subsequent calls to mDNS_RegisterService() if records
// need to be re-registered.
AuthRecord RR_ADV; // e.g. _services._dns-sd._udp.local. PTR _printer._tcp.local.
AuthRecord RR_PTR; // e.g. _printer._tcp.local. PTR Name._printer._tcp.local.
@@ -1781,10 +1679,21 @@ typedef struct
typedef enum
{
- LLQ_InitialRequest = 1,
- LLQ_SecondaryRequest = 2,
- LLQ_Established = 3,
- LLQ_Poll = 4
+ // This is the initial state.
+ LLQ_Init = 1,
+
+ // All of these states indicate that we are doing DNS Push, and haven't given up yet.
+ LLQ_DNSPush_ServerDiscovery = 100,
+ LLQ_DNSPush_Connecting = 101,
+ LLQ_DNSPush_Established = 102,
+
+ // All of these states indicate that we are doing LLQ and haven't given up yet.
+ LLQ_InitialRequest = 200,
+ LLQ_SecondaryRequest = 201,
+ LLQ_Established = 202,
+
+ // If we get here, it means DNS Push isn't available, so we're polling.
+ LLQ_Poll = 300
} LLQ_State;
// LLQ constants
@@ -1811,23 +1720,15 @@ enum
enum { NoAnswer_Normal = 0, NoAnswer_Suspended = 1, NoAnswer_Fail = 2 };
-// DNS Push Notification
-typedef enum
-{
- DNSPUSH_NOERROR = 0,
- DNSPUSH_FORMERR = 1,
- DNSPUSH_SERVFAIL = 2,
- DNSPUSH_NOTIMP = 4,
- DNSPUSH_REFUSED = 5
-} DNSPUSH_ErrorCode;
-
typedef enum {
- DNSPUSH_INIT = 1,
- DNSPUSH_NOSERVER = 2,
- DNSPUSH_SERVERFOUND = 3,
- DNSPUSH_ESTABLISHED = 4
-} DNSPush_State;
-
+ DNSPushServerDisconnected,
+ DNSPushServerConnectFailed,
+ DNSPushServerConnectionInProgress,
+ DNSPushServerConnected,
+ DNSPushServerSessionEstablished,
+ DNSPushServerNoDNSPush
+} DNSPushServer_ConnectState;
+
enum {
AllowExpired_None = 0, // Don't allow expired answers or mark answers immortal (behave normally)
AllowExpired_MakeAnswersImmortal = 1, // Any answers to this question get marked as immortal
@@ -1840,26 +1741,11 @@ typedef mDNSu8 AllowExpiredState;
#define HMAC_OPAD 0x5c
#define MD5_LEN 16
-#define AutoTunnelUnregistered(X) ( \
- (X)->AutoTunnelHostRecord.resrec.RecordType == kDNSRecordTypeUnregistered && \
- (X)->AutoTunnelTarget.resrec.RecordType == kDNSRecordTypeUnregistered && \
- (X)->AutoTunnelDeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered && \
- (X)->AutoTunnelService.resrec.RecordType == kDNSRecordTypeUnregistered && \
- (X)->AutoTunnel6Record.resrec.RecordType == kDNSRecordTypeUnregistered )
-
// Internal data structure to maintain authentication information
typedef struct DomainAuthInfo
{
struct DomainAuthInfo *next;
mDNSs32 deltime; // If we're planning to delete this DomainAuthInfo, the time we want it deleted
- mDNSBool AutoTunnel; // Whether this is AutoTunnel
- AuthRecord AutoTunnelHostRecord; // User-visible hostname; used as SRV target for AutoTunnel services
- AuthRecord AutoTunnelTarget; // Opaque hostname of tunnel endpoint; used as SRV target for AutoTunnelService record
- AuthRecord AutoTunnelDeviceInfo; // Device info of tunnel endpoint
- AuthRecord AutoTunnelService; // Service record (possibly NAT-Mapped) of IKE daemon implementing tunnel endpoint
- AuthRecord AutoTunnel6Record; // AutoTunnel AAAA Record obtained from awacsd
- mDNSBool AutoTunnelServiceStarted; // Whether a service has been registered in this domain
- mDNSv6Addr AutoTunnelInnerAddress;
domainname domain;
domainname keyname;
domainname hostname;
@@ -1874,64 +1760,55 @@ typedef struct DomainAuthInfo
// layer. These values are used within mDNSResponder and not sent across to the application. QC_addnocache is for
// delivering a response without adding to the cache. QC_forceresponse is superset of QC_addnocache where in
// addition to not entering in the cache, it also forces the negative response through.
-typedef enum { QC_rmv = 0, QC_add, QC_addnocache, QC_forceresponse, QC_dnssec , QC_nodnssec, QC_suppressed } QC_result;
+typedef enum { QC_rmv = 0, QC_add, QC_addnocache, QC_forceresponse, QC_suppressed } QC_result;
typedef void mDNSQuestionCallback (mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord);
+typedef void (*mDNSQuestionResetHandler)(DNSQuestion *question);
typedef void AsyncDispatchFunc(mDNS *const m, void *context);
-typedef void DNSSECAuthInfoFreeCallback(mDNS *const m, void *context);
extern void mDNSPlatformDispatchAsync(mDNS *const m, void *context, AsyncDispatchFunc func);
#define NextQSendTime(Q) ((Q)->LastQTime + (Q)->ThisQInterval)
#define ActiveQuestion(Q) ((Q)->ThisQInterval > 0 && !(Q)->DuplicateOf)
#define TimeToSendThisQuestion(Q,time) (ActiveQuestion(Q) && (time) - NextQSendTime(Q) >= 0)
-// q->ValidationStatus is either DNSSECValNotRequired or DNSSECValRequired and then moves onto DNSSECValInProgress.
-// When Validation is done, we mark all "DNSSECValInProgress" questions "DNSSECValDone". If we are answering
-// questions from /etc/hosts, then we go straight to DNSSECValDone from the initial state.
-typedef enum { DNSSECValNotRequired = 0, DNSSECValRequired, DNSSECValInProgress, DNSSECValDone } DNSSECValState;
-
-// ValidationRequired can be set to the following values:
-//
-// SECURE validation is set to determine whether something is secure or bogus
-// INSECURE validation is set internally by dnssec code to indicate that it is currently proving something
-// is insecure
-#define DNSSEC_VALIDATION_NONE 0x00
-#define DNSSEC_VALIDATION_SECURE 0x01
-#define DNSSEC_VALIDATION_SECURE_OPTIONAL 0x02
-#define DNSSEC_VALIDATION_INSECURE 0x03
-
-// For both ValidationRequired and ValidatingResponse question, we validate DNSSEC responses.
-// For ProxyQuestion with DNSSECOK, we just receive the DNSSEC records to pass them along without
-// validation and if the CD bit is not set, we also validate.
-#define DNSSECQuestion(q) ((q)->ValidationRequired || (q)->ValidatingResponse || ((q)->ProxyQuestion && (q)->ProxyDNSSECOK))
-
-// ValidatingQuestion is used when we need to know whether we are validating the DNSSEC responses for a question
-#define ValidatingQuestion(q) ((q)->ValidationRequired || (q)->ValidatingResponse)
-
-#define DNSSECOptionalQuestion(q) ((q)->ValidationRequired == DNSSEC_VALIDATION_SECURE_OPTIONAL)
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+#define FollowCNAMEOptionDNSSEC(Q) !(Q)->DNSSECStatus.enable_dnssec
+#else // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+#define FollowCNAMEOptionDNSSEC(Q) mDNStrue
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
// Given the resource record and the question, should we follow the CNAME ?
#define FollowCNAME(q, rr, AddRecord) (AddRecord && (q)->qtype != kDNSType_CNAME && \
(rr)->RecordType != kDNSRecordTypePacketNegative && \
- (rr)->rrtype == kDNSType_CNAME)
+ (rr)->rrtype == kDNSType_CNAME \
+ && FollowCNAMEOptionDNSSEC(q))
// RFC 4122 defines it to be 16 bytes
#define UUID_SIZE 16
-#define AWD_METRICS (USE_AWD && TARGET_OS_IOS)
-
-#if AWD_METRICS
-
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
enum
{
ExpiredAnswer_None = 0, // No expired answers used
ExpiredAnswer_Allowed = 1, // An expired answer is allowed by this request
- ExpiredAnswer_AnsweredWithExpired = 2, // Question was answered with an expired answer
- ExpiredAnswer_ExpiredAnswerChanged = 3, // Expired answer changed on refresh
+ ExpiredAnswer_AnsweredWithCache = 2, // Question was answered with a cached answer
+ ExpiredAnswer_AnsweredWithExpired = 3, // Question was answered with an expired answer
+ ExpiredAnswer_ExpiredAnswerChanged = 4, // Expired answer changed on refresh
ExpiredAnswer_EnumCount
};
typedef mDNSu8 ExpiredAnswerMetric;
+enum
+{
+ DNSOverTCP_None = 0, // DNS Over TCP not used
+ DNSOverTCP_Truncated = 1, // DNS Over TCP used because UDP reply was truncated
+ DNSOverTCP_Suspicious = 2, // DNS Over TCP used because we received a suspicious reply
+ DNSOverTCP_SuspiciousDefense = 3, // DNS Over TCP used because we were within the timeframe of a previous suspicious response
+
+ DNSOverTCP_EnumCount
+};
+typedef mDNSu8 DNSOverTCPMetric;
+
typedef struct
{
domainname * originalQName; // Name of original A/AAAA record if this question is for a CNAME record.
@@ -1939,21 +1816,22 @@ typedef struct
mDNSs32 firstQueryTime; // The time when the first query was sent to a DNS server.
mDNSBool answered; // Has this question been answered?
ExpiredAnswerMetric expiredAnswerState; // Expired answer state (see ExpiredAnswerMetric above)
-
+ DNSOverTCPMetric dnsOverTCPState; // DNS Over TCP state (see DNSOverTCPMetric above)
+
} uDNSMetrics;
#endif
-// DNS64 code is only for iOS, which is currently the only Apple OS that supports DNS proxy network extensions.
-#define USE_DNS64 (HAVE_DNS64 && TARGET_OS_IOS)
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
+extern mDNSu32 curr_num_regservices; // tracks the current number of services registered
+extern mDNSu32 max_num_regservices; // tracks the max number of simultaneous services registered by the device
+#endif
-#if USE_DNS64
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
#include "DNS64State.h"
#endif
-#if TARGET_OS_EMBEDDED
-extern mDNSu32 curr_num_regservices; // tracks the current number of services registered
-extern mDNSu32 max_num_regservices; // tracks the max number of simultaneous services registered by the device
-#endif
+typedef struct mDNS_DNSPushNotificationServer DNSPushNotificationServer;
+typedef struct mDNS_DNSPushNotificationZone DNSPushNotificationZone;
struct DNSQuestion_struct
{
@@ -1979,7 +1857,6 @@ struct DNSQuestion_struct
DomainAuthInfo *AuthInfo; // Non-NULL if query is currently being done using Private DNS
DNSQuestion *DuplicateOf;
DNSQuestion *NextInDQList;
- AnonymousInfo *AnonInfo; // Anonymous Information
DupSuppressInfo DupSuppress[DupSuppressInfoSize];
mDNSInterfaceID SendQNow; // The interface this query is being sent on right now
mDNSBool SendOnAll; // Set if we're sending this question on all active interfaces
@@ -1988,29 +1865,28 @@ struct DNSQuestion_struct
mDNSu32 RequestUnicast; // Non-zero if we want to send query with kDNSQClass_UnicastResponse bit set
mDNSs32 LastQTxTime; // Last time this Q was sent on one (but not necessarily all) interfaces
mDNSu32 CNAMEReferrals; // Count of how many CNAME redirections we've done
- mDNSBool SuppressQuery; // This query should be suppressed and not sent on the wire
+ mDNSBool Suppressed; // This query should be suppressed, i.e., not sent on the wire.
mDNSu8 LOAddressAnswers; // Number of answers from the local only auth records that are
// answering A, AAAA, CNAME, or PTR (/etc/hosts)
mDNSu8 WakeOnResolveCount; // Number of wakes that should be sent on resolve
+ mDNSBool InitialCacheMiss; // True after the question cannot be answered from the cache
mDNSs32 StopTime; // Time this question should be stopped by giving them a negative answer
- // DNSSEC fields
- DNSSECValState ValidationState; // Current state of the Validation process
- DNSSECStatus ValidationStatus; // Validation status for "ValidationRequired" questions (dnssec)
- mDNSu8 ValidatingResponse; // Question trying to validate a response (dnssec) on behalf of
- // ValidationRequired question
- void *DNSSECAuthInfo;
- DNSSECAuthInfoFreeCallback *DAIFreeCallback;
-
// Wide Area fields. These are used internally by the uDNS core (Unicast)
UDPSocket *LocalSocket;
// |-> DNS Configuration related fields used in uDNS (Subset of Wide Area/Unicast fields)
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ mdns_dns_service_t dnsservice; // The current DNS service.
+ mdns_dns_service_id_t lastDNSServiceID; // The ID of the previous DNS service before a CNAME restart.
+ mdns_querier_t querier; // The current querier.
+#else
DNSServer *qDNSServer; // Caching server for this query (in the absence of an SRV saying otherwise)
mDNSOpaque128 validDNSServers; // Valid DNSServers for this question
mDNSu16 noServerResponse; // At least one server did not respond.
- mDNSu16 triedAllServersOnce; // Tried all DNS servers once
+ mDNSBool triedAllServersOnce; // True if all DNS servers have been tried once.
mDNSu8 unansweredQueries; // The number of unanswered queries to this server
+#endif
AllowExpiredState allowExpired; // Allow expired answers state (see enum AllowExpired_None, etc. above)
ZoneData *nta; // Used for getting zone data for private or LLQ query
@@ -2020,7 +1896,9 @@ struct DNSQuestion_struct
mDNSIPPort tcpSrcPort; // Local Port TCP packet received on;need this as tcp struct is disposed
// by tcpCallback before calling into mDNSCoreReceive
mDNSu8 NoAnswer; // Set if we want to suppress answers until tunnel setup has completed
- mDNSu8 Restart; // This question should be restarted soon
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ mDNSBool Restart; // This question should be restarted soon.
+#endif
// LLQ-specific fields. These fields are only meaningful when LongLived flag is set
LLQ_State state;
@@ -2032,24 +1910,24 @@ struct DNSQuestion_struct
// the number of packets sent for this TCP/TLS connection
// DNS Push Notification fields. These fields are only meaningful when LongLived flag is set
- DNSPush_State dnsPushState; // The state of the DNS push notification negotiation
- mDNSAddr dnsPushServerAddr; // Address of the system acting as the DNS Push Server
- mDNSIPPort dnsPushServerPort; // Port on which the DNS Push Server is being advertised.
-
+ DNSPushNotificationServer *dnsPushServer;
+
mDNSOpaque64 id;
// DNS Proxy fields
mDNSOpaque16 responseFlags; // Temporary place holder for the error we get back from the DNS server
// till we populate in the cache
- mDNSBool DisallowPID; // Is the query allowed for the "PID" that we are sending on behalf of ?
+ mDNSBool BlockedByPolicy; // True if the question is blocked by policy rule evaluation.
mDNSs32 ServiceID; // Service identifier to match against the DNS server
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ mDNSu8 ResolverUUID[UUID_SIZE]; // Resolver UUID to match against the DNS server
+ mdns_dns_service_id_t CustomID;
+#endif
// Client API fields: The client must set up these fields *before* calling mDNS_StartQuery()
mDNSInterfaceID InterfaceID; // Non-zero if you want to issue queries only on a single specific IP interface
mDNSu32 flags; // flags from original DNSService*() API request.
- mDNSAddr Target; // Non-zero if you want to direct queries to a specific unicast target address
- mDNSIPPort TargetPort; // Must be set if Target is set
- mDNSOpaque16 TargetQID; // Must be set if Target is set
+ mDNSOpaque16 TargetQID; // DNS or mDNS message ID.
domainname qname;
domainname firstExpiredQname; // first expired qname in request chain
mDNSu16 qtype;
@@ -2059,28 +1937,37 @@ struct DNSQuestion_struct
mDNSBool ForceMCast; // Set by client to force mDNS query, even for apparently uDNS names
mDNSBool ReturnIntermed; // Set by client to request callbacks for intermediate CNAME/NXDOMAIN results
mDNSBool SuppressUnusable; // Set by client to suppress unusable queries to be sent on the wire
- mDNSu8 RetryWithSearchDomains; // Retry with search domains if there is no entry in the cache or AuthRecords
- mDNSu8 TimeoutQuestion; // Timeout this question if there is no reply in configured time
- mDNSu8 WakeOnResolve; // Send wakeup on resolve
- mDNSu8 UseBackgroundTrafficClass; // Set by client to use background traffic class for request
- mDNSs8 SearchListIndex; // Index into SearchList; Used by the client layer but not touched by core
- mDNSs8 AppendSearchDomains; // Search domains can be appended for this query
- mDNSs8 AppendLocalSearchDomains; // Search domains ending in .local can be appended for this query
- mDNSu8 ValidationRequired; // Requires DNSSEC validation.
+ mDNSBool TimeoutQuestion; // Timeout this question if there is no reply in configured time
+ mDNSBool IsUnicastDotLocal; // True if this is a dot-local query that should be answered via unicast DNS.
+ mDNSBool WakeOnResolve; // Send wakeup on resolve
+ mDNSBool UseBackgroundTraffic; // Set by client to use background traffic class for request
+ mDNSBool AppendSearchDomains; // Search domains can be appended for this query
+ mDNSBool ForcePathEval; // Perform a path evaluation even if kDNSServiceFlagsPathEvaluationDone is set.
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ mDNSBool RequireEncryption; // Set by client to require encrypted queries
+#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
+ mDNSBool inAppBrowserRequest; // Is request associated with an in-app-browser
+ audit_token_t peerAuditToken; // audit token of the peer requesting the question
+ audit_token_t delegateAuditToken; // audit token of the delegated client the question is for
+#endif
mDNSu8 ProxyQuestion; // Proxy Question
- mDNSu8 ProxyDNSSECOK; // Proxy Question with EDNS0 DNSSEC OK bit set
mDNSs32 pid; // Process ID of the client that is requesting the question
mDNSu8 uuid[UUID_SIZE]; // Unique ID of the client that is requesting the question (valid only if pid is zero)
mDNSu32 euid; // Effective User Id of the client that is requesting the question
- domainname *qnameOrig; // Copy of the original question name if it is not fully qualified
+ mDNSu32 request_id; // The ID of request that generates the current question
mDNSQuestionCallback *QuestionCallback;
+ mDNSQuestionResetHandler ResetHandler;
void *QuestionContext;
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
uDNSMetrics metrics; // Data used for collecting unicast DNS query metrics.
#endif
-#if USE_DNS64
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
DNS64 dns64; // DNS64 state for performing IPv6 address synthesis on networks with NAT64.
#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+ dnssec_status_t DNSSECStatus; // DNSSEC state for fectching DNSSEC records and doing validation
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
};
typedef enum { ZoneServiceUpdate, ZoneServiceQuery, ZoneServiceLLQ, ZoneServiceDNSPush } ZoneService;
@@ -2174,7 +2061,9 @@ struct NetworkInterfaceInfo_struct
// Standard AuthRecords that every Responder host should have (one per active IP address)
AuthRecord RR_A; // 'A' or 'AAAA' (address) record for our ".local" name
AuthRecord RR_PTR; // PTR (reverse lookup) record
- AuthRecord RR_HINFO;
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ AuthRecord RR_AddrRand; // For non-AWDL interfaces, this is the A or AAAA record of the randomized hostname.
+#endif
// Client API fields: The client must set up these fields *before* calling mDNS_RegisterInterface()
mDNSInterfaceID InterfaceID; // Identifies physical interface; MUST NOT be 0, -1, or -2
@@ -2240,48 +2129,6 @@ enum
SleepState_Sleeping = 2
};
-typedef enum
-{
- kStatsActionIncrement,
- kStatsActionDecrement,
- kStatsActionClear,
- kStatsActionSet
-} DNSSECStatsAction;
-
-typedef enum
-{
- kStatsTypeMemoryUsage,
- kStatsTypeLatency,
- kStatsTypeExtraPackets,
- kStatsTypeStatus,
- kStatsTypeProbe,
- kStatsTypeMsgSize
-} DNSSECStatsType;
-
-typedef struct
-{
- mDNSu32 TotalMemUsed;
- mDNSu32 Latency0; // 0 to 4 ms
- mDNSu32 Latency5; // 5 to 9 ms
- mDNSu32 Latency10; // 10 to 19 ms
- mDNSu32 Latency20; // 20 to 49 ms
- mDNSu32 Latency50; // 50 to 99 ms
- mDNSu32 Latency100; // >= 100 ms
- mDNSu32 ExtraPackets0; // 0 to 2 packets
- mDNSu32 ExtraPackets3; // 3 to 6 packets
- mDNSu32 ExtraPackets7; // 7 to 9 packets
- mDNSu32 ExtraPackets10; // >= 10 packets
- mDNSu32 SecureStatus;
- mDNSu32 InsecureStatus;
- mDNSu32 IndeterminateStatus;
- mDNSu32 BogusStatus;
- mDNSu32 NoResponseStatus;
- mDNSu32 NumProbesSent; // Number of probes sent
- mDNSu32 MsgSize0; // DNSSEC message size <= 1024
- mDNSu32 MsgSize1; // DNSSEC message size <= 2048
- mDNSu32 MsgSize2; // DNSSEC message size > 2048
-} DNSSECStatistics;
-
typedef struct
{
mDNSu32 NameConflicts; // Normal Name conflicts
@@ -2307,27 +2154,7 @@ typedef struct
mDNSu32 WakeOnResolves; // Number of times we did a wake on resolve
} mDNSStatistics;
-extern void LogMDNSStatistics(mDNS *const m);
-
-typedef struct mDNS_DNSPushNotificationServer DNSPushNotificationServer;
-typedef struct mDNS_DNSPushNotificationZone DNSPushNotificationZone;
-
-struct mDNS_DNSPushNotificationServer
-{
- mDNSAddr serverAddr; // Server Address
- tcpInfo_t *connection; // TCP Connection pointer
- mDNSu32 numberOfQuestions; // Number of questions for this server
- DNSPushNotificationServer *next;
-} ;
-
-struct mDNS_DNSPushNotificationZone
-{
- domainname zoneName;
- DNSPushNotificationServer *servers; // DNS Push Notification Servers for this zone
- mDNSu32 numberOfQuestions; // Number of questions for this zone
- DNSPushNotificationZone *next;
-} ;
-
+extern void LogMDNSStatisticsToFD(int fd, mDNS *const m);
// Time constant (~= 260 hours ~= 10 days and 21 hours) used to set
// various time values to a point well into the future.
@@ -2358,10 +2185,6 @@ struct mDNS_struct
mDNSu8 lock_rrcache; // For debugging: Set at times when these lists may not be modified
mDNSu8 lock_Questions;
mDNSu8 lock_Records;
-#ifndef MaxMsg
- #define MaxMsg 512
-#endif
- char MsgBuffer[MaxMsg]; // Temp storage used while building error log messages
// Task Scheduling variables
mDNSs32 timenow_adjust; // Correction applied if we ever discover time went backwards
@@ -2377,11 +2200,10 @@ struct mDNS_struct
mDNSs32 NextScheduledNATOp; // Next time to send NAT-traversal packets
mDNSs32 NextScheduledSPS; // Next time to purge expiring Sleep Proxy records
mDNSs32 NextScheduledKA; // Next time to send Keepalive packets (SPS)
-#if BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
mDNSs32 NextBonjourDisableTime; // Next time to leave multicast group if Bonjour on Demand is enabled
mDNSu8 BonjourEnabled; // Non zero if Bonjour is currently enabled by the Bonjour on Demand logic
-#endif // BONJOUR_ON_DEMAND
- mDNSs32 DelayConflictProcessing; // To prevent spurious confilcts due to stale packets on the wire/air.
+#endif
mDNSs32 RandomQueryDelay; // For de-synchronization of query packets on the wire
mDNSu32 RandomReconfirmDelay; // For de-synchronization of reconfirmation queries on the wire
mDNSs32 PktNum; // Unique sequence number assigned to each received packet
@@ -2416,7 +2238,6 @@ struct mDNS_struct
DNSQuestion *LocalOnlyQuestions; // Questions with InterfaceID set to mDNSInterface_LocalOnly or mDNSInterface_P2P
DNSQuestion *NewLocalOnlyQuestions; // Fresh local-only or P2P questions not yet answered
DNSQuestion *RestartQuestion; // Questions that are being restarted (stop followed by start)
- DNSQuestion *ValidationQuestion; // Questions that are being validated (dnssec)
mDNSu32 rrcache_size; // Total number of available cache entries
mDNSu32 rrcache_totalused; // Number of cache entries currently occupied
mDNSu32 rrcache_totalused_unicast; // Number of cache entries currently occupied by unicast
@@ -2432,6 +2253,14 @@ struct mDNS_struct
domainlabel nicelabel; // Rich text label encoded using canonically precomposed UTF-8
domainlabel hostlabel; // Conforms to RFC 1034 "letter-digit-hyphen" ARPANET host name rules
domainname MulticastHostname; // Fully Qualified "dot-local" Host Name, e.g. "Foo.local."
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ domainname RandomizedHostname; // Randomized hostname to use for services involving AWDL interfaces. This is to
+ // avoid using a hostname derived from the device's name, which may contain the
+ // owner's real name, (e.g., "Steve's iPhone" -> "Steves-iPhone.local"), which is a
+ // privacy concern.
+ mDNSu32 AutoTargetAWDLIncludedCount;// Number of registered AWDL-included auto-target records.
+ mDNSu32 AutoTargetAWDLOnlyCount; // Number of registered AWDL-only auto-target records.
+#endif
UTF8str255 HIHardware;
UTF8str255 HISoftware;
AuthRecord DeviceInfo;
@@ -2450,7 +2279,9 @@ struct mDNS_struct
mDNSs32 NextuDNSEvent; // uDNS next event
mDNSs32 NextSRVUpdate; // Time to perform delayed update
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
DNSServer *DNSServers; // list of DNS servers
+#endif
McastResolver *McastResolvers; // list of Mcast Resolvers
mDNSAddr Router;
@@ -2464,8 +2295,6 @@ struct mDNS_struct
domainname StaticHostname; // Current answer to reverse-map query
domainname FQDN;
HostnameInfo *Hostnames; // List of registered hostnames + hostname metadata
- NATTraversalInfo AutoTunnelNAT; // Shared between all AutoTunnel DomainAuthInfo structs
- mDNSv6Addr AutoTunnelRelayAddr;
mDNSu32 WABBrowseQueriesCount; // Number of WAB Browse domain enumeration queries (b, db) callers
mDNSu32 WABLBrowseQueriesCount; // Number of legacy WAB Browse domain enumeration queries (lb) callers
@@ -2523,26 +2352,23 @@ struct mDNS_struct
int ProxyRecords; // Total number of records we're holding as proxy
#define MAX_PROXY_RECORDS 10000 /* DOS protection: 400 machines at 25 records each */
-#if APPLE_OSX_mDNSResponder
- ClientTunnel *TunnelClients;
- void *WCF;
+#if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
+ WCFConnection *WCF;
#endif
// DNS Proxy fields
mDNSu32 dp_ipintf[MaxIp]; // input interface index list from the DNS Proxy Client
mDNSu32 dp_opintf; // output interface index from the DNS Proxy Client
- TrustAnchor *TrustAnchors;
int notifyToken;
int uds_listener_skt; // Listening socket for incoming UDS clients. This should not be here -- it's private to uds_daemon.c and nothing to do with mDNSCore -- SC
mDNSu32 AutoTargetServices; // # of services that have AutoTarget set
-#if BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
// Counters used in Bonjour on Demand logic.
mDNSu32 NumAllInterfaceRecords; // Right now we count *all* multicast records here. Later we may want to change to count interface-specific records separately. (This count includes records on the DuplicateRecords list too.)
mDNSu32 NumAllInterfaceQuestions; // Right now we count *all* multicast questions here. Later we may want to change to count interface-specific questions separately.
-#endif // BONJOUR_ON_DEMAND
+#endif
- DNSSECStatistics DNSSECStats;
mDNSStatistics mDNSStats;
// Fixed storage, to avoid creating large objects on the stack
@@ -2550,6 +2376,11 @@ struct mDNS_struct
union { DNSMessage m; void *p; } imsg; // Incoming message received from wire
DNSMessage omsg; // Outgoing message we're building
LargeCacheRecord rec; // Resource Record extracted from received message
+
+#ifndef MaxMsg
+ #define MaxMsg 512
+#endif
+ char MsgBuffer[MaxMsg]; // Temp storage used while building error log messages (keep at end of struct)
};
#define FORALL_CACHERECORDS(SLOT,CG,CR) \
@@ -2565,13 +2396,12 @@ struct mDNS_struct
extern const mDNSInterfaceID mDNSInterface_Any; // Zero
extern const mDNSInterfaceID mDNSInterface_LocalOnly; // Special value
-extern const mDNSInterfaceID mDNSInterface_Unicast; // Special value
extern const mDNSInterfaceID mDNSInterfaceMark; // Special value
extern const mDNSInterfaceID mDNSInterface_P2P; // Special value
extern const mDNSInterfaceID uDNSInterfaceMark; // Special value
extern const mDNSInterfaceID mDNSInterface_BLE; // Special value
-#define LocalOnlyOrP2PInterface(INTERFACE) ((INTERFACE == mDNSInterface_LocalOnly) || (INTERFACE == mDNSInterface_P2P) || (INTERFACE == mDNSInterface_BLE))
+#define LocalOnlyOrP2PInterface(INTERFACE) (((INTERFACE) == mDNSInterface_LocalOnly) || ((INTERFACE) == mDNSInterface_P2P) || ((INTERFACE) == mDNSInterface_BLE))
extern const mDNSIPPort DiscardPort;
extern const mDNSIPPort SSHPort;
@@ -2609,21 +2439,17 @@ extern const mDNSOpaque16 zeroID;
extern const mDNSOpaque16 onesID;
extern const mDNSOpaque16 QueryFlags;
extern const mDNSOpaque16 uQueryFlags;
-extern const mDNSOpaque16 DNSSecQFlags;
extern const mDNSOpaque16 ResponseFlags;
extern const mDNSOpaque16 UpdateReqFlags;
extern const mDNSOpaque16 UpdateRespFlags;
extern const mDNSOpaque16 SubscribeFlags;
extern const mDNSOpaque16 UnSubscribeFlags;
+extern const mDNSOpaque16 uDNSSecQueryFlags;
extern const mDNSOpaque64 zeroOpaque64;
extern const mDNSOpaque128 zeroOpaque128;
extern mDNSBool StrictUnicastOrdering;
-extern mDNSu8 NumUnicastDNSServers;
-#if APPLE_OSX_mDNSResponder
-extern mDNSu8 NumUnreachableDNSServers;
-#endif
#define localdomain (*(const domainname *)"\x5" "local")
#define DeviceInfoName (*(const domainname *)"\xC" "_device-info" "\x4" "_tcp")
@@ -2646,6 +2472,9 @@ extern mDNSu8 NumUnreachableDNSServers;
// If we're not doing inline functions, then this header needs to have the extern declarations
#if !defined(mDNSinline)
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+extern int CountOfUnicastDNSServers(mDNS *const m);
+#endif
extern mDNSs32 NonZeroTime(mDNSs32 t);
extern mDNSu16 mDNSVal16(mDNSOpaque16 x);
extern mDNSOpaque16 mDNSOpaque16fromIntVal(mDNSu16 v);
@@ -2659,6 +2488,16 @@ extern mDNSOpaque16 mDNSOpaque16fromIntVal(mDNSu16 v);
#ifdef mDNSinline
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+mDNSinline int CountOfUnicastDNSServers(mDNS *const m)
+{
+ int count = 0;
+ DNSServer *ptr = m->DNSServers;
+ while(ptr) { if(!(ptr->flags & DNSServerFlag_Delete)) count++; ptr = ptr->next; }
+ return (count);
+}
+#endif
+
mDNSinline mDNSs32 NonZeroTime(mDNSs32 t) { if (t) return(t);else return(1);}
mDNSinline mDNSu16 mDNSVal16(mDNSOpaque16 x) { return((mDNSu16)((mDNSu16)x.b[0] << 8 | (mDNSu16)x.b[1])); }
@@ -2672,7 +2511,7 @@ mDNSinline mDNSOpaque16 mDNSOpaque16fromIntVal(mDNSu16 v)
}
#endif
-
+
// ***************************************************************************
#if 0
#pragma mark -
@@ -2813,7 +2652,6 @@ typedef enum { mDNS_Dereg_normal, mDNS_Dereg_rapid, mDNS_Dereg_conflict, mDNS_De
extern void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mDNSInterfaceID InterfaceID,
mDNSu16 rrtype, mDNSu32 ttl, mDNSu8 RecordType, AuthRecType artype, mDNSRecordCallback Callback, void *Context);
-extern mDNSu32 deriveD2DFlagsFromAuthRecType(AuthRecType authRecType);
extern mStatus mDNS_RegisterService (mDNS *const m, ServiceRecordSet *sr,
const domainlabel *const name, const domainname *const type, const domainname *const domain,
const domainname *const host, mDNSIPPort port, RData *txtrdata, const mDNSu8 txtinfo[], mDNSu16 txtlen,
@@ -2835,7 +2673,7 @@ extern void mDNS_SetupQuestion(DNSQuestion *const q, const mDNSInterfaceID Inter
const mDNSu16 qtype, mDNSQuestionCallback *const callback, void *const context);
extern mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question,
- const domainname *const srv, const domainname *const domain, const mDNSu8 *anondata,
+ const domainname *const srv, const domainname *const domain,
const mDNSInterfaceID InterfaceID, mDNSu32 flags,
mDNSBool ForceMCast, mDNSBool useBackgroundTrafficClass,
mDNSQuestionCallback *Callback, void *Context);
@@ -2864,8 +2702,14 @@ extern mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr, mDNS_DomainT
extern mDNSOpaque16 mDNS_NewMessageID(mDNS *const m);
extern mDNSBool mDNS_AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID InterfaceID, const mDNSAddr *addr);
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
extern DNSServer *GetServerForQuestion(mDNS *m, DNSQuestion *question);
+#endif
extern mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question);
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+extern mDNSBool ShouldSuppressUnicastQuery(const DNSQuestion *q, mdns_dns_service_t dnsservice);
+extern mDNSBool LocalRecordRmvEventsForQuestion(mDNS *m, DNSQuestion *q);
+#endif
// ***************************************************************************
#if 0
@@ -2884,6 +2728,10 @@ extern mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question);
// This macro uses mDNSPlatformMemCopy() to make sure it only touches the actual bytes that are valid.
#define AssignDomainName(DST, SRC) do { mDNSu16 len__ = DomainNameLength((SRC)); \
if (len__ <= MAX_DOMAIN_NAME) mDNSPlatformMemCopy((DST)->c, (SRC)->c, len__); else (DST)->c[0] = 0; } while(0)
+#define AssignConstStringDomainName(DST, SRC) do { \
+ mDNSu16 len__ = DomainNameLengthLimit((domainname *)(SRC), (mDNSu8 *)(SRC) + sizeof (SRC)); \
+ if (len__ <= MAX_DOMAIN_NAME) \
+ mDNSPlatformMemCopy((DST)->c, (SRC), len__); else (DST)->c[0] = 0; } while(0)
// Comparison functions
#define SameDomainLabelCS(A,B) ((A)[0] == (B)[0] && mDNSPlatformMemSame((A)+1, (B)+1, (A)[0]))
@@ -2971,8 +2819,10 @@ extern mDNSBool DeconstructServiceName(const domainname *const fqdn, domainlabel
// not the number of characters that *would* have been printed were buflen unlimited.
extern mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, va_list arg) IS_A_PRINTF_STYLE_FUNCTION(3,0);
extern mDNSu32 mDNS_snprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, ...) IS_A_PRINTF_STYLE_FUNCTION(3,4);
+extern void mDNS_snprintf_add(char **dst, const char *lim, const char *fmt, ...) IS_A_PRINTF_STYLE_FUNCTION(3,4);
extern mDNSu32 NumCacheRecordsForInterfaceID(const mDNS *const m, mDNSInterfaceID id);
extern char *DNSTypeName(mDNSu16 rrtype);
+extern const char *mStatusDescription(mStatus error);
extern char *GetRRDisplayString_rdb(const ResourceRecord *const rr, const RDataBody *const rd1, char *const buffer);
#define RRDisplayString(m, rr) GetRRDisplayString_rdb(rr, &(rr)->rdata->u, (m)->MsgBuffer)
#define ARDisplayString(m, rr) GetRRDisplayString_rdb(&(rr)->resrec, &(rr)->resrec.rdata->u, (m)->MsgBuffer)
@@ -2982,6 +2832,7 @@ extern mDNSBool mDNSSameAddress(const mDNSAddr *ip1, const mDNSAddr *ip2);
extern void IncrementLabelSuffix(domainlabel *name, mDNSBool RichText);
extern mDNSBool mDNSv4AddrIsRFC1918(const mDNSv4Addr * const addr); // returns true for RFC1918 private addresses
#define mDNSAddrIsRFC1918(X) ((X)->type == mDNSAddrType_IPv4 && mDNSv4AddrIsRFC1918(&(X)->ip.v4))
+extern const char *DNSScopeToString(mDNSu32 scope);
// For PCP
extern void mDNSAddrMapIPv4toIPv6(mDNSv4Addr* in, mDNSv6Addr* out);
@@ -3053,7 +2904,7 @@ extern mDNSBool mDNSAddrIPv4FromMappedIPv6(mDNSv6Addr *in, mDNSv4Addr *out);
// and the value is prepended to the IPSec identifier (used for key lookup)
extern mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info,
- const domainname *domain, const domainname *keyname, const char *b64keydata, const domainname *hostname, mDNSIPPort *port, mDNSBool autoTunnel);
+ const domainname *domain, const domainname *keyname, const char *b64keydata, const domainname *hostname, mDNSIPPort *port);
extern void RecreateNATMappings(mDNS *const m, const mDNSu32 waitTicks);
@@ -3077,10 +2928,12 @@ extern void RecreateNATMappings(mDNS *const m, const mDNSu32 waitTicks);
extern void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext);
extern void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn);
extern void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, const mDNSAddr *v6addr, const mDNSAddr *router);
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
extern DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, mDNSs32 serviceID, const mDNSAddr *addr,
- const mDNSIPPort port, mDNSu32 scoped, mDNSu32 timeout, mDNSBool cellIntf, mDNSBool isExpensive, mDNSBool isCLAT46,
- mDNSu16 resGroupID, mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO);
+ const mDNSIPPort port, ScopeType scopeType, mDNSu32 timeout, mDNSBool cellIntf, mDNSBool isExpensive, mDNSBool isConstrained, mDNSBool isCLAT46,
+ mDNSu32 resGroupID, mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO);
extern void PenalizeDNSServer(mDNS *const m, DNSQuestion *q, mDNSOpaque16 responseFlags);
+#endif
extern void mDNS_AddSearchDomain(const domainname *const domain, mDNSInterfaceID InterfaceID);
extern McastResolver *mDNS_AddMcastResolver(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, mDNSu32 timeout);
@@ -3107,9 +2960,6 @@ extern void DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, DomainAuthInfo
(M)->h.numAdditionals = (mDNSu16)((mDNSu8 *)&(M)->h.numAdditionals)[0] << 8 | ((mDNSu8 *)&(M)->h.numAdditionals)[1]; \
} while (0)
-#define DNSDigest_SignMessageHostByteOrder(M,E,INFO) \
- do { SwapDNSHeaderBytes(M); DNSDigest_SignMessage((M), (E), (INFO), 0); SwapDNSHeaderBytes(M); } while (0)
-
// verify a DNS message. The message must be complete, with all values in network byte order. end points to the
// end of the record. tsig is a pointer to the resource record that contains the TSIG OPT record. info is
// the matching key to use for verifying the message. This function expects that the additionals member
@@ -3151,6 +3001,17 @@ extern mDNSBool DNSDigest_VerifyMessage(DNSMessage *msg, mDNSu8 *end, LargeCache
//
// mDNSPlatformUTC returns the time, in seconds, since Jan 1st 1970 UTC and is required for generating TSIG records
+#ifdef MDNS_MALLOC_DEBUGGING
+typedef void mDNSListValidationFunction(void *);
+typedef struct listValidator mDNSListValidator;
+struct listValidator {
+ struct listValidator *next;
+ const char *validationFunctionName;
+ mDNSListValidationFunction *validator;
+ void *context;
+};
+#endif // MDNS_MALLOC_DEBUGGING
+
extern mStatus mDNSPlatformInit (mDNS *const m);
extern void mDNSPlatformClose (mDNS *const m);
extern mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
@@ -3160,7 +3021,6 @@ extern mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg,
extern void mDNSPlatformLock (const mDNS *const m);
extern void mDNSPlatformUnlock (const mDNS *const m);
-extern void mDNSPlatformStrCopy ( void *dst, const void *src);
extern mDNSu32 mDNSPlatformStrLCopy ( void *dst, const void *src, mDNSu32 len);
extern mDNSu32 mDNSPlatformStrLen ( const void *src);
extern void mDNSPlatformMemCopy ( void *dst, const void *src, mDNSu32 len);
@@ -3168,12 +3028,18 @@ extern mDNSBool mDNSPlatformMemSame (const void *dst, const void *src, mDNSu
extern int mDNSPlatformMemCmp (const void *dst, const void *src, mDNSu32 len);
extern void mDNSPlatformMemZero ( void *dst, mDNSu32 len);
extern void mDNSPlatformQsort (void *base, int nel, int width, int (*compar)(const void *, const void *));
-#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
-#define mDNSPlatformMemAllocate(X) mallocL(# X, X)
+#if MDNS_MALLOC_DEBUGGING
+#define mDNSPlatformMemAllocate(X) mallocL(# X, X)
+#define mDNSPlatformMemAllocateClear(X) callocL(# X, X)
+#define mDNSPlatformMemFree(X) freeL(# X, X)
+extern void mDNSPlatformValidateLists (void);
+extern void mDNSPlatformAddListValidator(mDNSListValidator *validator,
+ mDNSListValidationFunction *vf, const char *vfName, void *context);
#else
-extern void * mDNSPlatformMemAllocate (mDNSu32 len);
-#endif
-extern void mDNSPlatformMemFree (void *mem);
+extern void * mDNSPlatformMemAllocate(mDNSu32 len);
+extern void * mDNSPlatformMemAllocateClear(mDNSu32 len);
+extern void mDNSPlatformMemFree(void *mem);
+#endif // MDNS_MALLOC_DEBUGGING
// If the platform doesn't have a strong PRNG, we define a naive multiply-and-add based on a seed
// from the platform layer. Long-term, we should embed an arc4 implementation, but the strength
@@ -3227,10 +3093,17 @@ typedef enum
} TCPSocketFlags;
typedef void (*TCPConnectionCallback)(TCPSocket *sock, void *context, mDNSBool ConnectionEstablished, mStatus err);
-extern TCPSocket *mDNSPlatformTCPSocket(TCPSocketFlags flags, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass); // creates a TCP socket
+typedef void (*TCPAcceptedCallback)(TCPSocket *sock, mDNSAddr *addr, mDNSIPPort *port,
+ const char *remoteName, void *context);
+extern TCPSocket *mDNSPlatformTCPSocket(TCPSocketFlags flags, mDNSAddr_Type addrtype, mDNSIPPort *port, domainname *hostname, mDNSBool useBackgroundTrafficClass); // creates a TCP socket
+extern TCPListener *mDNSPlatformTCPListen(mDNSAddr_Type addrtype, mDNSIPPort *port, mDNSAddr *addr,
+ TCPSocketFlags socketFlags, mDNSBool reuseAddr, int queueLength,
+ TCPAcceptedCallback callback, void *context); // Listen on a port
+extern mStatus mDNSPlatformTCPSocketSetCallback(TCPSocket *sock, TCPConnectionCallback callback, void *context);
extern TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int sd);
extern int mDNSPlatformTCPGetFD(TCPSocket *sock);
-extern mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, domainname *hostname,
+extern mDNSBool mDNSPlatformTCPWritable(TCPSocket *sock);
+extern mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport,
mDNSInterfaceID InterfaceID, TCPConnectionCallback callback, void *context);
extern void mDNSPlatformTCPCloseConnection(TCPSocket *sock);
extern long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed);
@@ -3259,7 +3132,7 @@ extern void mDNSPlatformTLSTearDownCerts(void);
// in browse/registration calls must implement these routines to get the "default" browse/registration list.
extern mDNSBool mDNSPlatformSetDNSConfig(mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains,
- DNameListElem **BrowseDomains, mDNSBool ackConfig);
+ DNameListElem **BrowseDomains, mDNSBool ackConfig);
extern mStatus mDNSPlatformGetPrimaryInterface(mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *router);
extern void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status);
@@ -3268,13 +3141,17 @@ extern void mDNSPlatformPreventSleep(mDNSu32 timeout, const char *reason);
extern void mDNSPlatformSendWakeupPacket(mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration);
extern mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID);
-extern mDNSBool mDNSPlatformInterfaceIsAWDL(const NetworkInterfaceInfo *intf);
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+extern mDNSBool mDNSPlatformInterfaceIsAWDL(mDNSInterfaceID interfaceID);
+#endif
extern mDNSBool mDNSPlatformValidRecordForQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
extern mDNSBool mDNSPlatformValidRecordForInterface(const AuthRecord *rr, mDNSInterfaceID InterfaceID);
extern mDNSBool mDNSPlatformValidQuestionForInterface(DNSQuestion *q, const NetworkInterfaceInfo *intf);
extern void mDNSPlatformFormatTime(unsigned long t, mDNSu8 *buf, int bufsize);
+// Platform event API
+
#ifdef _LEGACY_NAT_TRAVERSAL_
// Support for legacy NAT traversal protocols, implemented by the platform layer and callable by the core.
extern void LNT_SendDiscoveryMsg(mDNS *m);
@@ -3338,6 +3215,12 @@ extern void mDNSCoreInitComplete(mDNS *const m, mStatus result);
extern void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
const mDNSAddr *const srcaddr, const mDNSIPPort srcport,
const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID);
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+extern void mDNSCoreReceiveForQuerier(mDNS *m, DNSMessage *msg, const mDNSu8 *end, mdns_querier_t querier, mdns_dns_service_t service);
+#endif
+extern CacheRecord *mDNSCheckCacheFlushRecords(mDNS *m, CacheRecord *CacheFlushRecords, mDNSBool id_is_zero, int numAnswers,
+ DNSQuestion *unicastQuestion, CacheRecord *NSECCachePtr, CacheRecord *NSECRecords,
+ mDNSu8 rcode);
extern void mDNSCoreRestartQueries(mDNS *const m);
extern void mDNSCoreRestartQuestion(mDNS *const m, DNSQuestion *q);
extern void mDNSCoreRestartRegistration(mDNS *const m, AuthRecord *rr, int announceCount);
@@ -3348,7 +3231,18 @@ extern void mDNSCoreRestartAddressQueries(mDNS *const m, mDNSBool SearchDoma
extern mDNSBool mDNSCoreHaveAdvertisedMulticastServices(mDNS *const m);
extern void mDNSCoreMachineSleep(mDNS *const m, mDNSBool wake);
extern mDNSBool mDNSCoreReadyForSleep(mDNS *m, mDNSs32 now);
-extern mDNSs32 mDNSCoreIntervalToNextWake(mDNS *const m, mDNSs32 now);
+
+typedef enum
+{
+ mDNSNextWakeReason_Null = 0,
+ mDNSNextWakeReason_NATPortMappingRenewal = 1,
+ mDNSNextWakeReason_RecordRegistrationRenewal = 2,
+ mDNSNextWakeReason_UpkeepWake = 3,
+ mDNSNextWakeReason_DHCPLeaseRenewal = 4,
+ mDNSNextWakeReason_SleepProxyRegistrationRetry = 5
+} mDNSNextWakeReason;
+
+extern mDNSs32 mDNSCoreIntervalToNextWake(mDNS *const m, mDNSs32 now, mDNSNextWakeReason *outReason);
extern void mDNSCoreReceiveRawPacket (mDNS *const m, const mDNSu8 *const p, const mDNSu8 *const end, const mDNSInterfaceID InterfaceID);
@@ -3360,14 +3254,20 @@ extern void ReleaseCacheRecord(mDNS *const m, CacheRecord *r);
extern void ScheduleNextCacheCheckTime(mDNS *const m, const mDNSu32 slot, const mDNSs32 event);
extern void SetNextCacheCheckTimeForRecord(mDNS *const m, CacheRecord *const rr);
extern void GrantCacheExtensions(mDNS *const m, DNSQuestion *q, mDNSu32 lease);
-extern void MakeNegativeCacheRecord(mDNS *const m, CacheRecord *const cr,
- const domainname *const name, const mDNSu32 namehash, const mDNSu16 rrtype, const mDNSu16 rrclass, mDNSu32 ttl_seconds,
- mDNSInterfaceID InterfaceID, DNSServer *dnsserver);
+extern void MakeNegativeCacheRecord(mDNS *const m, CacheRecord *const cr, const domainname *const name,
+ const mDNSu32 namehash, const mDNSu16 rrtype, const mDNSu16 rrclass, mDNSu32 ttl_seconds, mDNSInterfaceID InterfaceID,
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ mdns_dns_service_t service);
+#else
+ DNSServer *dnsserver);
+#endif
extern void CompleteDeregistration(mDNS *const m, AuthRecord *rr);
extern void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheRecord *const rr, const QC_result AddRecord);
extern void AnswerQuestionByFollowingCNAME(mDNS *const m, DNSQuestion *q, ResourceRecord *rr);
extern char *InterfaceNameForID(mDNS *const m, const mDNSInterfaceID InterfaceID);
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
extern void DNSServerChangeForQuestion(mDNS *const m, DNSQuestion *q, DNSServer *newServer);
+#endif
extern void ActivateUnicastRegistration(mDNS *const m, AuthRecord *const rr);
extern void CheckSuppressUnusableQuestions(mDNS *const m);
extern void RetrySearchDomainQuestions(mDNS *const m);
@@ -3383,26 +3283,12 @@ extern AuthGroup *AuthGroupForName(AuthHash *r, const mDNSu32 namehash, const do
extern AuthGroup *AuthGroupForRecord(AuthHash *r, const ResourceRecord *const rr);
extern AuthGroup *InsertAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr);
extern AuthGroup *RemoveAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr);
-extern mDNSBool mDNS_CheckForCacheRecord(mDNS *const m, DNSQuestion *q, mDNSu16 qtype);
-// For now this AutoTunnel stuff is specific to Mac OS X.
-// In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer
#if APPLE_OSX_mDNSResponder
-extern void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord);
-extern void AddNewClientTunnel(DNSQuestion *const q);
-extern void StartServerTunnel(DomainAuthInfo *const info);
-extern void UpdateAutoTunnelDomainStatuses(const mDNS *const m);
-extern void RemoveAutoTunnel6Record(mDNS *const m);
-extern mDNSBool RecordReadyForSleep(AuthRecord *rr);
// For now this LocalSleepProxy stuff is specific to Mac OS X.
// In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer
extern mStatus ActivateLocalProxy(NetworkInterfaceInfo *const intf, mDNSBool offloadKeepAlivesOnly, mDNSBool *keepaliveOnly);
-extern void mDNSPlatformUpdateDNSStatus(DNSQuestion *q);
-extern void mDNSPlatformTriggerDNSRetry(DNSQuestion *v4q, DNSQuestion *v6q);
-extern void mDNSPlatformLogToFile(int log_level, const char *buffer);
extern mDNSBool SupportsInNICProxy(NetworkInterfaceInfo *const intf);
-extern mStatus SymptomReporterDNSServerReachable(mDNS *const m, const mDNSAddr *addr);
-extern mStatus SymptomReporterDNSServerUnreachable(DNSServer *s);
#endif
typedef void ProxyCallback (void *socket, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr,
@@ -3413,12 +3299,19 @@ extern void mDNSPlatformDisposeProxyContext(void *context);
extern mDNSu8 *DNSProxySetAttributes(DNSQuestion *q, DNSMessageHeader *h, DNSMessage *msg, mDNSu8 *start, mDNSu8 *limit);
#if APPLE_OSX_mDNSResponder
-extern void mDNSPlatformGetDNSRoutePolicy(DNSQuestion *q, mDNSBool *isBlocked);
+extern void mDNSPlatformGetDNSRoutePolicy(DNSQuestion *q);
#endif
extern void mDNSPlatformSetSocktOpt(void *sock, mDNSTransport_Type transType, mDNSAddr_Type addrType, const DNSQuestion *q);
extern mDNSs32 mDNSPlatformGetPID(void);
extern mDNSBool mDNSValidKeepAliveRecord(AuthRecord *rr);
extern mDNSBool CacheRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q);
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+extern void GetRandomUUIDLabel(domainlabel *label);
+extern void GetRandomUUIDLocalHostname(domainname *hostname);
+#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
+extern void uDNSMetricsClear(uDNSMetrics *metrics);
+#endif
// ***************************************************************************
#if 0
@@ -3580,7 +3473,7 @@ typedef struct MD5state_st
mDNSu32 A,B,C,D;
mDNSu32 Nl,Nh;
mDNSu32 data[MD5_BLOCK_LONG];
- int num;
+ mDNSu32 num;
} MD5_CTX;
extern int MD5_Init(MD5_CTX *c);
@@ -3627,7 +3520,6 @@ struct CompileTimeAssertionChecks_mDNS
char assertL[(sizeof(IKEHeader ) == 28 ) ? 1 : -1];
char assertM[(sizeof(TCPHeader ) == 20 ) ? 1 : -1];
char assertN[(sizeof(rdataOPT) == 24 ) ? 1 : -1];
- char assertO[(sizeof(rdataRRSig) == 20 ) ? 1 : -1];
char assertP[(sizeof(PCPMapRequest) == 60 ) ? 1 : -1];
char assertQ[(sizeof(PCPMapReply) == 60 ) ? 1 : -1];
@@ -3637,38 +3529,33 @@ struct CompileTimeAssertionChecks_mDNS
// cause structure sizes (and therefore memory usage) to balloon unreasonably.
char sizecheck_RDataBody [(sizeof(RDataBody) == 264) ? 1 : -1];
char sizecheck_ResourceRecord [(sizeof(ResourceRecord) <= 72) ? 1 : -1];
- char sizecheck_AuthRecord [(sizeof(AuthRecord) <= 1208) ? 1 : -1];
+ char sizecheck_AuthRecord [(sizeof(AuthRecord) <= 1176) ? 1 : -1];
char sizecheck_CacheRecord [(sizeof(CacheRecord) <= 232) ? 1 : -1];
char sizecheck_CacheGroup [(sizeof(CacheGroup) <= 232) ? 1 : -1];
- char sizecheck_DNSQuestion [(sizeof(DNSQuestion) <= 1168) ? 1 : -1];
-
- char sizecheck_ZoneData [(sizeof(ZoneData) <= 2000) ? 1 : -1];
+ char sizecheck_DNSQuestion [(sizeof(DNSQuestion) <= 1216) ? 1 : -1];
+ char sizecheck_ZoneData [(sizeof(ZoneData) <= 2048) ? 1 : -1];
char sizecheck_NATTraversalInfo [(sizeof(NATTraversalInfo) <= 200) ? 1 : -1];
char sizecheck_HostnameInfo [(sizeof(HostnameInfo) <= 3050) ? 1 : -1];
- char sizecheck_DNSServer [(sizeof(DNSServer) <= 330) ? 1 : -1];
- char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <= 8400) ? 1 : -1];
- char sizecheck_ServiceRecordSet [(sizeof(ServiceRecordSet) <= 5540) ? 1 : -1];
- char sizecheck_DomainAuthInfo [(sizeof(DomainAuthInfo) <= 7888) ? 1 : -1];
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ char sizecheck_DNSServer [(sizeof(DNSServer) <= 328) ? 1 : -1];
+#endif
+ char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <= 9000) ? 1 : -1];
+ char sizecheck_ServiceRecordSet [(sizeof(ServiceRecordSet) <= 4760) ? 1 : -1];
+ char sizecheck_DomainAuthInfo [(sizeof(DomainAuthInfo) <= 944) ? 1 : -1];
#if APPLE_OSX_mDNSResponder
- char sizecheck_ClientTunnel [(sizeof(ClientTunnel) <= 1512) ? 1 : -1];
+ char sizecheck_ClientTunnel [(sizeof(ClientTunnel) <= 1560) ? 1 : -1];
+#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+ // structure size is assumed by LogRedact routine.
+ char sizecheck_mDNSAddr [(sizeof(mDNSAddr) == 20) ? 1 : -1];
+ char sizecheck_mDNSv4Addr [(sizeof(mDNSv4Addr) == 4) ? 1 : -1];
+ char sizecheck_mDNSv6Addr [(sizeof(mDNSv6Addr) == 16) ? 1 : -1];
#endif
};
// Routine to initialize device-info TXT record contents
mDNSu32 initializeDeviceInfoTXT(mDNS *m, mDNSu8 *ptr);
-#if APPLE_OSX_mDNSResponder
-extern void D2D_start_advertising_interface(NetworkInterfaceInfo *interface);
-extern void D2D_stop_advertising_interface(NetworkInterfaceInfo *interface);
-extern void D2D_start_advertising_record(AuthRecord *ar);
-extern void D2D_stop_advertising_record(AuthRecord *ar);
-#else
-#define D2D_start_advertising_interface(X)
-#define D2D_stop_advertising_interface(X)
-#define D2D_start_advertising_record(X)
-#define D2D_stop_advertising_record(X)
-#endif
-
// ***************************************************************************
#ifdef __cplusplus
diff --git a/usr/src/contrib/mDNSResponder/mDNSCore/nsec.h b/usr/src/contrib/mDNSResponder/mDNSCore/nsec.h
deleted file mode 100644
index 198f57db92..0000000000
--- a/usr/src/contrib/mDNSResponder/mDNSCore/nsec.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2011-2012 Apple Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __NSEC_H
-#define __NSEC_H
-
-#include "dnssec.h"
-
-extern mDNSBool AddNSECSForCacheRecord(mDNS *const m, CacheRecord *crlist, CacheRecord *negcr, mDNSu8 rcode);
-extern void WildcardAnswerProof(mDNS *const m, DNSSECVerifier *dv);
-extern void ValidateWithNSECS(mDNS *const m, DNSSECVerifier *dv, CacheRecord *rr);
-extern mDNSBool NSECAnswersDS(mDNS *const m, ResourceRecord *rr, DNSQuestion *q);
-extern int CountLabelsMatch(const domainname *const d1, const domainname *const d2);
-extern void NameErrorNSECCallback(mDNS *const m, DNSSECVerifier *dv, DNSSECStatus status);
-extern void VerifyNSEC(mDNS *const m, ResourceRecord *rr, RRVerifier *rv, DNSSECVerifier *pdv, CacheRecord *ncr,
- DNSSECVerifierCallback callback);
-extern CacheRecord *NSECRecordIsDelegation(mDNS *const m, domainname *name, mDNSu16 qtype);
-extern void NoDataNSECCallback(mDNS *const m, DNSSECVerifier *dv, DNSSECStatus status);
-
-#endif // __NSEC_H
diff --git a/usr/src/contrib/mDNSResponder/mDNSCore/uDNS.c b/usr/src/contrib/mDNSResponder/mDNSCore/uDNS.c
index 84913404d4..3892582a73 100755
--- a/usr/src/contrib/mDNSResponder/mDNSCore/uDNS.c
+++ b/usr/src/contrib/mDNSResponder/mDNSCore/uDNS.c
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2017 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2002-2020 Apple Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,15 +19,24 @@
* Any dynamic run-time requirements should be handled by the platform layer below or client layer above
*/
-#if APPLE_OSX_mDNSResponder
-#include <TargetConditionals.h>
-#endif
#include "uDNS.h"
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
#include "Metrics.h"
#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, SYMPTOMS)
+#include "SymptomReporter.h"
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+#include "QuerierSupport.h"
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+#include "dnssec_v2.h"
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+
#if (defined(_MSC_VER))
// Disable "assignment within conditional expression".
// Other compilers understand the convention that if you place the assignment expression within an extra pair
@@ -48,16 +56,14 @@ mDNSexport SearchListElem *SearchList = mDNSNULL;
// The value can be set to true by the Platform code e.g., MacOSX uses the plist mechanism
mDNSBool StrictUnicastOrdering = mDNSfalse;
+extern mDNS mDNSStorage;
+
// We keep track of the number of unicast DNS servers and log a message when we exceed 64.
// Currently the unicast queries maintain a 128 bit map to track the valid DNS servers for that
// question. Bit position is the index into the DNS server list. This is done so to try all
// the servers exactly once before giving up. If we could allocate memory in the core, then
// arbitrary limitation of 128 DNSServers can be removed.
-mDNSu8 NumUnicastDNSServers = 0;
#define MAX_UNICAST_DNS_SERVERS 128
-#if APPLE_OSX_mDNSResponder
-mDNSu8 NumUnreachableDNSServers = 0;
-#endif
#define SetNextuDNSEvent(m, rr) { \
if ((m)->NextuDNSEvent - ((rr)->LastAPTime + (rr)->ThisAPInterval) >= 0) \
@@ -115,111 +121,115 @@ mDNSlocal void SetRecordRetry(mDNS *const m, AuthRecord *rr, mDNSu32 random)
#pragma mark - Name Server List Management
#endif
-#define TrueFalseStr(X) ((X) ? "true" : "false")
-
-mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSs32 serviceID, const mDNSAddr *addr,
- const mDNSIPPort port, mDNSu32 scoped, mDNSu32 timeout, mDNSBool cellIntf, mDNSBool isExpensive, mDNSBool isCLAT46,
- mDNSu16 resGroupID, mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO)
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *domain, const mDNSInterfaceID interface,
+ const mDNSs32 serviceID, const mDNSAddr *addr, const mDNSIPPort port, ScopeType scopeType, mDNSu32 timeout,
+ mDNSBool isCell, mDNSBool isExpensive, mDNSBool isConstrained, mDNSBool isCLAT46, mDNSu32 resGroupID,
+ mDNSBool usableA, mDNSBool usableAAAA, mDNSBool reqDO)
{
- DNSServer **p = &m->DNSServers;
- DNSServer *tmp = mDNSNULL;
-
- if ((NumUnicastDNSServers + 1) > MAX_UNICAST_DNS_SERVERS)
+ DNSServer **p;
+ DNSServer *server;
+ int dnsCount = CountOfUnicastDNSServers(m);
+ if (dnsCount >= MAX_UNICAST_DNS_SERVERS)
{
- LogMsg("mDNS_AddDNSServer: DNS server limit of %d reached, not adding this server", MAX_UNICAST_DNS_SERVERS);
+ LogMsg("mDNS_AddDNSServer: DNS server count of %d reached, not adding this server", dnsCount);
return mDNSNULL;
}
- if (!d)
- d = (const domainname *)"";
-
- LogInfo("mDNS_AddDNSServer(%d): Adding %#a for %##s, InterfaceID %p, serviceID %u, scoped %d, resGroupID %d req_A %s, req_AAAA %s, cell %s, expensive %s, CLAT46 %s, req_DO %s",
- NumUnicastDNSServers, addr, d->c, interface, serviceID, scoped, resGroupID,
- TrueFalseStr(reqA), TrueFalseStr(reqAAAA), TrueFalseStr(cellIntf), TrueFalseStr(isExpensive), TrueFalseStr(isCLAT46), TrueFalseStr(reqDO));
+ if (!domain) domain = (const domainname *)"";
+
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "mDNS_AddDNSServer(%d): Adding " PRI_IP_ADDR " for " PRI_DM_NAME " interface " PUB_S " (%p), serviceID %u, "
+ "scopeType %d, resGroupID %u" PUB_S PUB_S PUB_S PUB_S PUB_S PUB_S PUB_S,
+ dnsCount + 1, addr, DM_NAME_PARAM(domain), InterfaceNameForID(&mDNSStorage, interface), interface, serviceID,
+ (int)scopeType, resGroupID,
+ usableA ? ", usableA" : "",
+ usableAAAA ? ", usableAAAA" : "",
+ isCell ? ", cell" : "",
+ isExpensive ? ", expensive" : "",
+ isConstrained ? ", constrained" : "",
+ isCLAT46 ? ", CLAT46" : "",
+ reqDO ? ", reqDO" : "");
+
+ // Scan our existing list to see if we already have a matching record for this DNS resolver
+ for (p = &m->DNSServers; (server = *p) != mDNSNULL; p = &server->next)
+ {
+ if (server->interface != interface) continue;
+ if (server->serviceID != serviceID) continue;
+ if (!mDNSSameAddress(&server->addr, addr)) continue;
+ if (!mDNSSameIPPort(server->port, port)) continue;
+ if (!SameDomainName(&server->domain, domain)) continue;
+ if (server->scopeType != scopeType) continue;
+ if (server->timeout != timeout) continue;
+ if (!server->usableA != !usableA) continue;
+ if (!server->usableAAAA != !usableAAAA) continue;
+ if (!server->isCell != !isCell) continue;
+ if (!(server->flags & DNSServerFlag_Delete))
+ {
+ debugf("Note: DNS Server %#a:%d for domain %##s (%p) registered more than once",
+ addr, mDNSVal16(port), domain->c, interface);
+ }
+ // If we found a matching record, cut it from the list
+ // (and if we’re *not* resurrecting a record that was marked for deletion, it’s a duplicate,
+ // and the debugf message signifies that we’re collapsing duplicate entries into one)
+ *p = server->next;
+ server->next = mDNSNULL;
+ break;
+ }
- while (*p) // Check if we already have this {interface,address,port,domain} tuple registered + reqA/reqAAAA bits
+ // If we broke out because we found an existing matching record, advance our pointer to the end of the list
+ while (*p)
{
- if ((*p)->scoped == scoped && (*p)->interface == interface && (*p)->serviceID == serviceID &&
- mDNSSameAddress(&(*p)->addr, addr) && mDNSSameIPPort((*p)->port, port) && SameDomainName(&(*p)->domain, d) &&
- (*p)->req_A == reqA && (*p)->req_AAAA == reqAAAA)
- {
- if (!((*p)->flags & DNSServer_FlagDelete))
- debugf("Note: DNS Server %#a:%d for domain %##s (%p) registered more than once", addr, mDNSVal16(port), d->c, interface);
- tmp = *p;
- *p = tmp->next;
- tmp->next = mDNSNULL;
- }
- else
- {
- p=&(*p)->next;
- }
+ p = &(*p)->next;
}
- // NumUnicastDNSServers is the count of active DNS servers i.e., ones that are not marked
- // with DNSServer_FlagDelete. We should increment it:
- //
- // 1) When we add a new DNS server
- // 2) When we resurrect a old DNS server that is marked with DNSServer_FlagDelete
- //
- // Don't increment when we resurrect a DNS server that is not marked with DNSServer_FlagDelete.
- // We have already accounted for it when it was added for the first time. This case happens when
- // we add DNS servers with the same address multiple times (mis-configuration).
-
- if (!tmp || (tmp->flags & DNSServer_FlagDelete))
- NumUnicastDNSServers++;
-
-
- if (tmp)
+ if (server)
{
-#if APPLE_OSX_mDNSResponder
- if (tmp->flags & DNSServer_FlagDelete)
+ if (server->flags & DNSServerFlag_Delete)
{
- tmp->flags &= ~DNSServer_FlagUnreachable;
- }
+#if MDNSRESPONDER_SUPPORTS(APPLE, SYMPTOMS)
+ server->flags &= ~DNSServerFlag_Unreachable;
#endif
- tmp->flags &= ~DNSServer_FlagDelete;
- *p = tmp; // move to end of list, to ensure ordering from platform layer
+ server->flags &= ~DNSServerFlag_Delete;
+ }
+ server->isExpensive = isExpensive;
+ server->isConstrained = isConstrained;
+ server->isCLAT46 = isCLAT46;
+ *p = server; // Append resurrected record at end of list
}
else
{
- // allocate, add to list
- *p = mDNSPlatformMemAllocate(sizeof(**p));
- if (!*p)
+ server = (DNSServer *) mDNSPlatformMemAllocateClear(sizeof(*server));
+ if (!server)
{
LogMsg("Error: mDNS_AddDNSServer - malloc");
}
else
{
- (*p)->scoped = scoped;
- (*p)->interface = interface;
- (*p)->serviceID = serviceID;
- (*p)->addr = *addr;
- (*p)->port = port;
- (*p)->flags = DNSServer_FlagNew;
- (*p)->timeout = timeout;
- (*p)->cellIntf = cellIntf;
- (*p)->isExpensive = isExpensive;
- (*p)->isCLAT46 = isCLAT46;
- (*p)->req_A = reqA;
- (*p)->req_AAAA = reqAAAA;
- (*p)->req_DO = reqDO;
- // We start off assuming that the DNS server is not DNSSEC aware and
- // when we receive the first response to a DNSSEC question, we set
- // it to true.
- (*p)->DNSSECAware = mDNSfalse;
- (*p)->retransDO = 0;
- AssignDomainName(&(*p)->domain, d);
- (*p)->next = mDNSNULL;
- }
- }
- if (*p) {
- (*p)->penaltyTime = 0;
- // We always update the ID (not just when we allocate a new instance) because we could
- // be adding a new non-scoped resolver with a new ID and we want all the non-scoped
- // resolvers belong to the same group.
- (*p)->resGroupID = resGroupID;
- }
- return(*p);
+ server->interface = interface;
+ server->serviceID = serviceID;
+ server->addr = *addr;
+ server->port = port;
+ server->scopeType = scopeType;
+ server->timeout = timeout;
+ server->usableA = usableA;
+ server->usableAAAA = usableAAAA;
+ server->isCell = isCell;
+ server->isExpensive = isExpensive;
+ server->isConstrained = isConstrained;
+ server->isCLAT46 = isCLAT46;
+ AssignDomainName(&server->domain, domain);
+ *p = server; // Append new record at end of list
+ }
+ }
+ if (server)
+ {
+ server->penaltyTime = 0;
+ // We always update the ID (not just when we allocate a new instance) because we want
+ // all the resGroupIDs for a particular domain to match.
+ server->resGroupID = resGroupID;
+ }
+ return(server);
}
// PenalizeDNSServer is called when the number of queries to the unicast
@@ -233,8 +243,9 @@ mDNSexport void PenalizeDNSServer(mDNS *const m, DNSQuestion *q, mDNSOpaque16 re
mDNS_CheckLock(m);
- LogInfo("PenalizeDNSServer: Penalizing DNS server %#a question for question %p %##s (%s) SuppressUnusable %d",
- (q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL), q, q->qname.c, DNSTypeName(q->qtype), q->SuppressUnusable);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "PenalizeDNSServer: Penalizing DNS server " PRI_IP_ADDR " question for question %p " PRI_DM_NAME " (" PUB_S ") SuppressUnusable %d",
+ (q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL), q, DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype), q->SuppressUnusable);
// If we get error from any DNS server, remember the error. If all of the servers,
// return the error, then return the first error.
@@ -257,27 +268,34 @@ mDNSexport void PenalizeDNSServer(mDNS *const m, DNSQuestion *q, mDNSOpaque16 re
if (!StrictUnicastOrdering)
{
- LogInfo("PenalizeDNSServer: Strict Unicast Ordering is FALSE");
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "PenalizeDNSServer: Strict Unicast Ordering is FALSE");
// We penalize the server so that new queries don't pick this server for DNSSERVER_PENALTY_TIME
// XXX Include other logic here to see if this server should really be penalized
//
if (q->qtype == kDNSType_PTR)
{
- LogInfo("PenalizeDNSServer: Not Penalizing PTR question");
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "PenalizeDNSServer: Not Penalizing PTR question");
}
- else if ((rcode == kDNSFlag1_RC_FormErr) || (rcode == kDNSFlag1_RC_ServFail) || (rcode == kDNSFlag1_RC_NotImpl) || (rcode == kDNSFlag1_RC_Refused))
+ else if ((rcode == kDNSFlag1_RC_FormErr) || (rcode == kDNSFlag1_RC_ServFail) || (rcode == kDNSFlag1_RC_NotImpl))
{
- LogInfo("PenalizeDNSServer: Not Penalizing DNS Server since it at least responded with rcode %d", rcode);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "PenalizeDNSServer: Not Penalizing DNS Server since it at least responded with rcode %d", rcode);
}
else
{
- LogInfo("PenalizeDNSServer: Penalizing question type %d", q->qtype);
+ const char *reason = "";
+ if (rcode == kDNSFlag1_RC_Refused)
+ {
+ reason = " because server refused to answer";
+ }
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "PenalizeDNSServer: Penalizing question type %d" PUB_S,
+ q->qtype, reason);
q->qDNSServer->penaltyTime = NonZeroTime(m->timenow + DNSSERVER_PENALTY_TIME);
}
}
else
{
- LogInfo("PenalizeDNSServer: Strict Unicast Ordering is TRUE");
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "PenalizeDNSServer: Strict Unicast Ordering is TRUE");
}
end:
@@ -287,8 +305,9 @@ end:
{
if (new)
{
- LogMsg("PenalizeDNSServer: ERROR!! GetServerForQuestion returned the same server %#a:%d", &new->addr,
- mDNSVal16(new->port));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "PenalizeDNSServer: ERROR!! GetServerForQuestion returned the same server " PRI_IP_ADDR ":%d",
+ &new->addr, mDNSVal16(new->port));
q->ThisQInterval = 0; // Inactivate this question so that we dont bombard the network
}
else
@@ -298,7 +317,7 @@ end:
// is slow in responding and we have sent three queries. When we repeatedly call, it is
// okay to receive the same NULL DNS server. Next time we try to send the query, we will
// realize and re-initialize the DNS servers.
- LogInfo("PenalizeDNSServer: GetServerForQuestion returned the same server NULL");
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "PenalizeDNSServer: GetServerForQuestion returned the same server NULL");
}
}
else
@@ -308,8 +327,9 @@ end:
if (new)
{
- LogInfo("PenalizeDNSServer: Server for %##s (%s) changed to %#a:%d (%##s)",
- q->qname.c, DNSTypeName(q->qtype), &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "PenalizeDNSServer: Server for " PRI_DM_NAME " (" PUB_S ") changed to " PRI_IP_ADDR ":%d (" PRI_DM_NAME ")",
+ DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype), &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), DM_NAME_PARAM(&q->qDNSServer->domain));
// We want to try the next server immediately. As the question may already have backed off, reset
// the interval. We do this only the first time when we try all the DNS servers. Once we reached the end of
// list and retrying all the servers again e.g., at least one server failed to respond in the previous try, we
@@ -337,12 +357,15 @@ end:
// the next query will not happen until cache expiry. If it is a long lived question,
// AnswerCurrentQuestionWithResourceRecord will not set it to MaxQuestionInterval. In that case,
// we want the normal backoff to work.
- LogInfo("PenalizeDNSServer: Server for %p, %##s (%s) changed to NULL, Interval %d", q, q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "PenalizeDNSServer: Server for %p, " PRI_DM_NAME " (" PUB_S ") changed to NULL, Interval %d",
+ q, DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype), q->ThisQInterval);
}
q->unansweredQueries = 0;
}
}
+#endif // !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
@@ -377,7 +400,7 @@ mDNSexport DomainAuthInfo *GetAuthInfoForName_internal(mDNS *m, const domainname
// First purge any dead keys from the list
while (*p)
{
- if ((*p)->deltime && m->timenow - (*p)->deltime >= 0 && AutoTunnelUnregistered(*p))
+ if ((*p)->deltime && m->timenow - (*p)->deltime >= 0)
{
DNSQuestion *q;
DomainAuthInfo *info = *p;
@@ -415,15 +438,14 @@ mDNSexport DomainAuthInfo *GetAuthInfoForName(mDNS *m, const domainname *const n
// MUST be called with the lock held
mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info,
- const domainname *domain, const domainname *keyname, const char *b64keydata, const domainname *hostname, mDNSIPPort *port, mDNSBool autoTunnel)
+ const domainname *domain, const domainname *keyname, const char *b64keydata, const domainname *hostname, mDNSIPPort *port)
{
DNSQuestion *q;
DomainAuthInfo **p = &m->AuthInfoList;
if (!info || !b64keydata) { LogMsg("mDNS_SetSecretForDomain: ERROR: info %p b64keydata %p", info, b64keydata); return(mStatus_BadParamErr); }
- LogInfo("mDNS_SetSecretForDomain: domain %##s key %##s%s", domain->c, keyname->c, autoTunnel ? " AutoTunnel" : "");
+ LogInfo("mDNS_SetSecretForDomain: domain %##s key %##s", domain->c, keyname->c);
- info->AutoTunnel = autoTunnel;
AssignDomainName(&info->domain, domain);
AssignDomainName(&info->keyname, keyname);
if (hostname)
@@ -448,16 +470,6 @@ mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info,
while (*p && (*p) != info) p=&(*p)->next;
if (*p) {LogInfo("mDNS_SetSecretForDomain: Domain %##s Already in list", (*p)->domain.c); return(mStatus_AlreadyRegistered);}
- // Caution: Only zero AutoTunnelHostRecord.namestorage AFTER we've determined that this is a NEW DomainAuthInfo
- // being added to the list. Otherwise we risk smashing our AutoTunnel host records that are already active and in use.
- info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeUnregistered;
- info->AutoTunnelHostRecord.namestorage.c[0] = 0;
- info->AutoTunnelTarget.resrec.RecordType = kDNSRecordTypeUnregistered;
- info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeUnregistered;
- info->AutoTunnelService.resrec.RecordType = kDNSRecordTypeUnregistered;
- info->AutoTunnel6Record.resrec.RecordType = kDNSRecordTypeUnregistered;
- info->AutoTunnelServiceStarted = mDNSfalse;
- info->AutoTunnelInnerAddress = zerov6Addr;
info->next = mDNSNULL;
*p = info;
@@ -1003,9 +1015,6 @@ mDNSlocal void StartLLQPolling(mDNS *const m, DNSQuestion *q)
// we risk causing spurious "SendQueries didn't send all its queries" log messages
q->LastQTime = m->timenow - q->ThisQInterval + 1;
SetNextQueryTime(m, q);
-#if APPLE_OSX_mDNSResponder
- UpdateAutoTunnelDomainStatuses(m);
-#endif
}
mDNSlocal mDNSu8 *putLLQ(DNSMessage *const msg, mDNSu8 *ptr, const DNSQuestion *const question, const LLQOptData *const data)
@@ -1061,8 +1070,6 @@ mDNSlocal void sendChallengeResponse(mDNS *const m, DNSQuestion *const q, const
if (q->tcp) { LogMsg("sendChallengeResponse: ERROR!!: question %##s (%s) tcp non-NULL", q->qname.c, DNSTypeName(q->qtype)); return; }
- if (PrivateQuery(q)) { LogMsg("sendChallengeResponse: ERROR!!: Private Query %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return; }
-
if (q->ntries++ == kLLQ_MAX_TRIES)
{
LogMsg("sendChallengeResponse: %d failed attempts for LLQ %##s", kLLQ_MAX_TRIES, q->qname.c);
@@ -1091,7 +1098,7 @@ mDNSlocal void sendChallengeResponse(mDNS *const m, DNSQuestion *const q, const
responsePtr = putLLQ(&m->omsg, responsePtr, q, llq);
if (responsePtr)
{
- mStatus err = mDNSSendDNSMessage(m, &m->omsg, responsePtr, mDNSInterface_Any, q->LocalSocket, &q->servAddr, q->servPort, mDNSNULL, mDNSNULL, mDNSfalse);
+ mStatus err = mDNSSendDNSMessage(m, &m->omsg, responsePtr, mDNSInterface_Any, mDNSNULL, q->LocalSocket, &q->servAddr, q->servPort, mDNSNULL, mDNSfalse);
if (err) { LogMsg("sendChallengeResponse: mDNSSendDNSMessage%s failed: %d", q->tcp ? " (TCP)" : "", err); }
}
else StartLLQPolling(m,q);
@@ -1140,27 +1147,12 @@ mDNSlocal void recvSetupResponse(mDNS *const m, mDNSu8 rcode, DNSQuestion *const
}
else if (q->state == LLQ_SecondaryRequest)
{
- //LogInfo("Got LLQ_SecondaryRequest");
-
- // Fix this immediately if not sooner. Copy the id from the LLQOptData into our DNSQuestion struct. This is only
- // an issue for private LLQs, because we skip parts 2 and 3 of the handshake. This is related to a bigger
- // problem of the current implementation of TCP LLQ setup: we're not handling state transitions correctly
- // if the server sends back SERVFULL or STATIC.
- if (PrivateQuery(q))
- {
- LogInfo("Private LLQ_SecondaryRequest; copying id %08X%08X", llq->id.l[0], llq->id.l[1]);
- q->id = llq->id;
- }
-
if (llq->err) { LogMsg("ERROR: recvSetupResponse %##s (%s) code %d from server", q->qname.c, DNSTypeName(q->qtype), llq->err); StartLLQPolling(m,q); return; }
if (!mDNSSameOpaque64(&q->id, &llq->id))
{ LogMsg("recvSetupResponse - ID changed. discarding"); return; } // this can happen rarely (on packet loss + reordering)
q->state = LLQ_Established;
q->ntries = 0;
SetLLQTimer(m, q, llq);
-#if APPLE_OSX_mDNSResponder
- UpdateAutoTunnelDomainStatuses(m);
-#endif
}
}
@@ -1216,7 +1208,7 @@ mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *co
//debugf("Sending LLQ ack for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
InitializeDNSMessage(&m->omsg.h, msg->h.id, ResponseFlags);
ackEnd = putLLQ(&m->omsg, m->omsg.data, q, &opt->u.llq);
- if (ackEnd) mDNSSendDNSMessage(m, &m->omsg, ackEnd, mDNSInterface_Any, q->LocalSocket, srcaddr, srcport, mDNSNULL, mDNSNULL, mDNSfalse);
+ if (ackEnd) mDNSSendDNSMessage(m, &m->omsg, ackEnd, mDNSInterface_Any, mDNSNULL, q->LocalSocket, srcaddr, srcport, mDNSNULL, mDNSfalse);
m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
debugf("uDNS_LLQ_Events: q->state == LLQ_Established msg->h.id %d q->TargetQID %d", mDNSVal16(msg->h.id), mDNSVal16(q->TargetQID));
*matchQuestion = q;
@@ -1266,7 +1258,7 @@ mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *co
}
// Stub definition of TCPSocket_struct so we can access flags field. (Rest of TCPSocket_struct is platform-dependent.)
-struct TCPSocket_struct { TCPSocketFlags flags; /* ... */ };
+struct TCPSocket_struct { mDNSIPPort port; TCPSocketFlags flags; /* ... */ };
// tcpCallback is called to handle events (e.g. connection opening and data reception) on TCP connections for
// Private DNS operations -- private queries, private LLQs, private record updates and private service updates
@@ -1326,23 +1318,18 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs
}
else if (q)
{
+ mDNSOpaque16 HeaderFlags = uQueryFlags;
+
// LLQ Polling mode or non-LLQ uDNS over TCP
- InitializeDNSMessage(&tcpInfo->request.h, q->TargetQID, (DNSSECQuestion(q) ? DNSSecQFlags : uQueryFlags));
+ InitializeDNSMessage(&tcpInfo->request.h, q->TargetQID, HeaderFlags);
end = putQuestion(&tcpInfo->request, tcpInfo->request.data, tcpInfo->request.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
- if (DNSSECQuestion(q) && q->qDNSServer && !q->qDNSServer->cellIntf)
- {
- if (q->ProxyQuestion)
- end = DNSProxySetAttributes(q, &tcpInfo->request.h, &tcpInfo->request, end, tcpInfo->request.data + AbsoluteMaxDNSMessageData);
- else
- end = putDNSSECOption(&tcpInfo->request, end, tcpInfo->request.data + AbsoluteMaxDNSMessageData);
- }
AuthInfo = q->AuthInfo; // Need to add TSIG to this message
}
- err = mDNSSendDNSMessage(m, &tcpInfo->request, end, mDNSInterface_Any, mDNSNULL, &tcpInfo->Addr, tcpInfo->Port, sock, AuthInfo, mDNSfalse);
+ err = mDNSSendDNSMessage(m, &tcpInfo->request, end, mDNSInterface_Any, sock, mDNSNULL, &tcpInfo->Addr, tcpInfo->Port, AuthInfo, mDNSfalse);
if (err) { debugf("ERROR: tcpCallback: mDNSSendDNSMessage - %d", err); err = mStatus_UnknownErr; goto exit; }
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
if (mDNSSameIPPort(tcpInfo->Port, UnicastDNSPort))
{
MetricsUpdateDNSQuerySize((mDNSu32)(end - (mDNSu8 *)&tcpInfo->request));
@@ -1404,7 +1391,7 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs
if (tcpInfo->replylen < sizeof(DNSMessageHeader))
{ LogMsg("ERROR: tcpCallback - length too short (%d bytes)", tcpInfo->replylen); err = mStatus_UnknownErr; goto exit; }
- tcpInfo->reply = mDNSPlatformMemAllocate(tcpInfo->replylen);
+ tcpInfo->reply = (DNSMessage *) mDNSPlatformMemAllocate(tcpInfo->replylen);
if (!tcpInfo->reply) { LogMsg("ERROR: tcpCallback - malloc failed"); err = mStatus_NoMemoryErr; goto exit; }
}
@@ -1564,18 +1551,30 @@ mDNSlocal tcpInfo_t *MakeTCPConn(mDNS *const m, const DNSMessage *const msg, con
tcpInfo_t *info;
mDNSBool useBackgroundTrafficClass;
- useBackgroundTrafficClass = question ? question->UseBackgroundTrafficClass : mDNSfalse;
+ useBackgroundTrafficClass = question ? question->UseBackgroundTraffic : mDNSfalse;
if ((flags & kTCPSocketFlags_UseTLS) && (!hostname || !hostname->c[0]))
{ LogMsg("MakeTCPConn: TLS connection being setup with NULL hostname"); return mDNSNULL; }
- info = (tcpInfo_t *)mDNSPlatformMemAllocate(sizeof(tcpInfo_t));
+ info = (tcpInfo_t *) mDNSPlatformMemAllocateClear(sizeof(*info));
if (!info) { LogMsg("ERROR: MakeTCP - memallocate failed"); return(mDNSNULL); }
- mDNSPlatformMemZero(info, sizeof(tcpInfo_t));
+
+ if (msg)
+ {
+ const mDNSu8 *const start = (const mDNSu8 *)msg;
+ if ((end < start) || ((end - start) > (int)sizeof(info->request)))
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "MakeTCPConn: invalid DNS message pointers -- msg: %p, end: %p", msg, end);
+ mDNSPlatformMemFree(info);
+ return mDNSNULL;
+ }
+ info->requestLen = (int)(end - start);
+ mDNSPlatformMemCopy(&info->request, msg, info->requestLen);
+ }
info->m = m;
- info->sock = mDNSPlatformTCPSocket(flags, &srcport, useBackgroundTrafficClass);
- info->requestLen = 0;
+ info->sock = mDNSPlatformTCPSocket(flags, Addr->type, &srcport, hostname, useBackgroundTrafficClass);
info->question = question;
info->rr = rr;
info->Addr = *Addr;
@@ -1586,15 +1585,9 @@ mDNSlocal tcpInfo_t *MakeTCPConn(mDNS *const m, const DNSMessage *const msg, con
info->numReplies = 0;
info->SrcPort = srcport;
- if (msg)
- {
- info->requestLen = (int) (end - ((mDNSu8*)msg));
- mDNSPlatformMemCopy(&info->request, msg, info->requestLen);
- }
-
if (!info->sock) { LogMsg("MakeTCPConn: unable to create TCP socket"); mDNSPlatformMemFree(info); return(mDNSNULL); }
mDNSPlatformSetSocktOpt(info->sock, mDNSTransport_TCP, Addr->type, question);
- err = mDNSPlatformTCPConnect(info->sock, Addr, Port, hostname, (question ? question->InterfaceID : mDNSNULL), tcpCallback, info);
+ err = mDNSPlatformTCPConnect(info->sock, Addr, Port, (question ? question->InterfaceID : mDNSNULL), tcpCallback, info);
// Probably suboptimal here.
// Instead of returning mDNSNULL here on failure, we should probably invoke the callback with an error code.
@@ -1618,6 +1611,16 @@ mDNSexport void DisposeTCPConn(struct tcpInfo_t *tcp)
// Lock must be held
mDNSexport void startLLQHandshake(mDNS *m, DNSQuestion *q)
{
+ // States prior to LLQ_InitialRequest should not react to NAT Mapping changes.
+ // startLLQHandshake is never called with q->state < LLQ_InitialRequest except
+ // from LLQNATCallback. When we are actually trying to do LLQ, then q->state will
+ // be equal to or greater than LLQ_InitialRequest when LLQNATCallback calls
+ // startLLQHandshake.
+ if (q->state < LLQ_InitialRequest)
+ {
+ return;
+ }
+
if (m->LLQNAT.clientContext != mDNSNULL) // LLQNAT just started, give it some time
{
LogInfo("startLLQHandshake: waiting for NAT status for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
@@ -1650,77 +1653,40 @@ mDNSexport void startLLQHandshake(mDNS *m, DNSQuestion *q)
return;
}
- if (PrivateQuery(q))
+ debugf("startLLQHandshake: m->AdvertisedV4 %#a%s Server %#a:%d%s %##s (%s)",
+ &m->AdvertisedV4, mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) ? " (RFC 1918)" : "",
+ &q->servAddr, mDNSVal16(q->servPort), mDNSAddrIsRFC1918(&q->servAddr) ? " (RFC 1918)" : "",
+ q->qname.c, DNSTypeName(q->qtype));
+
+ if (q->ntries++ >= kLLQ_MAX_TRIES)
{
- if (q->tcp) LogInfo("startLLQHandshake: Disposing existing TCP connection for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- if (q->tcp) { DisposeTCPConn(q->tcp); q->tcp = mDNSNULL; }
- if (!q->nta)
- {
- // Normally we lookup the zone data and then call this function. And we never free the zone data
- // for "PrivateQuery". But sometimes this can happen due to some race conditions. When we
- // switch networks, we might end up "Polling" the network e.g., we are behind a Double NAT.
- // When we poll, we free the zone information as we send the query to the server (See
- // PrivateQueryGotZoneData). The NAT callback (LLQNATCallback) may happen soon after that. If we
- // are still behind Double NAT, we would have returned early in this function. But we could
- // have switched to a network with no NATs and we should get the zone data again.
- LogInfo("startLLQHandshake: nta is NULL for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- q->nta = StartGetZoneData(m, &q->qname, ZoneServiceLLQ, LLQGotZoneData, q);
- return;
- }
- else if (!q->nta->Host.c[0])
- {
- // This should not happen. If it happens, we print a log and MakeTCPConn will fail if it can't find a hostname
- LogMsg("startLLQHandshake: ERROR!!: nta non NULL for %##s (%s) but HostName %d NULL, LongLived %d", q->qname.c, DNSTypeName(q->qtype), q->nta->Host.c[0], q->LongLived);
- }
- q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &q->servAddr, q->servPort, &q->nta->Host, q, mDNSNULL);
- if (!q->tcp)
- q->ThisQInterval = mDNSPlatformOneSecond * 5; // If TCP failed (transient networking glitch) try again in five seconds
- else
- {
- q->state = LLQ_SecondaryRequest; // Right now, for private DNS, we skip the four-way LLQ handshake
- q->ReqLease = kLLQ_DefLease;
- q->ThisQInterval = 0;
- }
- q->LastQTime = m->timenow;
- SetNextQueryTime(m, q);
+ LogMsg("startLLQHandshake: %d failed attempts for LLQ %##s Polling.", kLLQ_MAX_TRIES, q->qname.c);
+ StartLLQPolling(m, q);
}
else
{
- debugf("startLLQHandshake: m->AdvertisedV4 %#a%s Server %#a:%d%s %##s (%s)",
- &m->AdvertisedV4, mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) ? " (RFC 1918)" : "",
- &q->servAddr, mDNSVal16(q->servPort), mDNSAddrIsRFC1918(&q->servAddr) ? " (RFC 1918)" : "",
- q->qname.c, DNSTypeName(q->qtype));
+ mDNSu8 *end;
+ LLQOptData llqData;
- if (q->ntries++ >= kLLQ_MAX_TRIES)
- {
- LogMsg("startLLQHandshake: %d failed attempts for LLQ %##s Polling.", kLLQ_MAX_TRIES, q->qname.c);
- StartLLQPolling(m, q);
- }
- else
- {
- mDNSu8 *end;
- LLQOptData llqData;
+ // set llq rdata
+ llqData.vers = kLLQ_Vers;
+ llqData.llqOp = kLLQOp_Setup;
+ llqData.err = LLQErr_NoError; // Don't need to tell server UDP notification port when sending over UDP
+ llqData.id = zeroOpaque64;
+ llqData.llqlease = kLLQ_DefLease;
- // set llq rdata
- llqData.vers = kLLQ_Vers;
- llqData.llqOp = kLLQOp_Setup;
- llqData.err = LLQErr_NoError; // Don't need to tell server UDP notification port when sending over UDP
- llqData.id = zeroOpaque64;
- llqData.llqlease = kLLQ_DefLease;
-
- InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags);
- end = putLLQ(&m->omsg, m->omsg.data, q, &llqData);
- if (!end) { LogMsg("ERROR: startLLQHandshake - putLLQ"); StartLLQPolling(m,q); return; }
+ InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags);
+ end = putLLQ(&m->omsg, m->omsg.data, q, &llqData);
+ if (!end) { LogMsg("ERROR: startLLQHandshake - putLLQ"); StartLLQPolling(m,q); return; }
- mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, q->LocalSocket, &q->servAddr, q->servPort, mDNSNULL, mDNSNULL, mDNSfalse);
+ mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, mDNSNULL, q->LocalSocket, &q->servAddr, q->servPort , mDNSNULL, mDNSfalse);
- // update question state
- q->state = LLQ_InitialRequest;
- q->ReqLease = kLLQ_DefLease;
- q->ThisQInterval = (kLLQ_INIT_RESEND * mDNSPlatformOneSecond);
- q->LastQTime = m->timenow;
- SetNextQueryTime(m, q);
- }
+ // update question state
+ q->state = LLQ_InitialRequest;
+ q->ReqLease = kLLQ_DefLease;
+ q->ThisQInterval = (kLLQ_INIT_RESEND * mDNSPlatformOneSecond);
+ q->LastQTime = m->timenow;
+ SetNextQueryTime(m, q);
}
}
@@ -1736,17 +1702,6 @@ mDNSexport const domainname *GetServiceTarget(mDNS *m, AuthRecord *const rr)
return(&rr->resrec.rdata->u.srv.target);
else
{
-#if APPLE_OSX_mDNSResponder
- DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, rr->resrec.name);
- if (AuthInfo && AuthInfo->AutoTunnel)
- {
- StartServerTunnel(AuthInfo);
- if (AuthInfo->AutoTunnelHostRecord.namestorage.c[0] == 0) return(mDNSNULL);
- debugf("GetServiceTarget: Returning %##s", AuthInfo->AutoTunnelHostRecord.namestorage.c);
- return(&AuthInfo->AutoTunnelHostRecord.namestorage);
- }
- else
-#endif // APPLE_OSX_mDNSResponder
{
const int srvcount = CountLabels(rr->resrec.name);
HostnameInfo *besthi = mDNSNULL, *hi;
@@ -1770,13 +1725,13 @@ mDNSexport const domainname *GetServiceTarget(mDNS *m, AuthRecord *const rr)
}
}
-mDNSlocal const domainname *PUBLIC_UPDATE_SERVICE_TYPE = (const domainname*)"\x0B_dns-update" "\x04_udp";
-mDNSlocal const domainname *PUBLIC_LLQ_SERVICE_TYPE = (const domainname*)"\x08_dns-llq" "\x04_udp";
+mDNSlocal const domainname *PUBLIC_UPDATE_SERVICE_TYPE = (const domainname*)"\x0B_dns-update" "\x04_udp";
+mDNSlocal const domainname *PUBLIC_LLQ_SERVICE_TYPE = (const domainname*)"\x08_dns-llq" "\x04_udp";
-mDNSlocal const domainname *PRIVATE_UPDATE_SERVICE_TYPE = (const domainname*)"\x0F_dns-update-tls" "\x04_tcp";
-mDNSlocal const domainname *PRIVATE_QUERY_SERVICE_TYPE = (const domainname*)"\x0E_dns-query-tls" "\x04_tcp";
-mDNSlocal const domainname *PRIVATE_LLQ_SERVICE_TYPE = (const domainname*)"\x0C_dns-llq-tls" "\x04_tcp";
-mDNSlocal const domainname *DNS_PUSH_NOTIFICATION_SERVICE_TYPE = (const domainname*)"\x0C_dns-push-tls" "\x04_tcp";
+mDNSlocal const domainname *PRIVATE_UPDATE_SERVICE_TYPE = (const domainname*)"\x0F_dns-update-tls" "\x04_tcp";
+mDNSlocal const domainname *PRIVATE_QUERY_SERVICE_TYPE = (const domainname*)"\x0E_dns-query-tls" "\x04_tcp";
+mDNSlocal const domainname *PRIVATE_LLQ_SERVICE_TYPE = (const domainname*)"\x0C_dns-llq-tls" "\x04_tcp";
+mDNSlocal const domainname *DNS_PUSH_NOTIFICATION_SERVICE_TYPE = (const domainname*)"\x0D_dns-push-tls" "\x04_tcp";
#define ZoneDataSRV(X) ( \
(X)->ZoneService == ZoneServiceUpdate ? ((X)->ZonePrivate ? PRIVATE_UPDATE_SERVICE_TYPE : PUBLIC_UPDATE_SERVICE_TYPE) : \
@@ -1809,25 +1764,13 @@ mDNSlocal void GetZoneData_QuestionCallback(mDNS *const m, DNSQuestion *question
{
AssignDomainName(&zd->ZoneName, answer->name);
zd->ZoneClass = answer->rrclass;
- AssignDomainName(&zd->question.qname, &zd->ZoneName);
GetZoneData_StartQuery(m, zd, kDNSType_SRV);
}
else if (zd->CurrentSOA->c[0])
{
- DomainAuthInfo *AuthInfo = GetAuthInfoForName(m, zd->CurrentSOA);
- if (AuthInfo && AuthInfo->AutoTunnel)
- {
- // To keep the load on the server down, we don't chop down on
- // SOA lookups for AutoTunnels
- LogInfo("GetZoneData_QuestionCallback: not chopping labels for %##s", zd->CurrentSOA->c);
- zd->ZoneDataCallback(m, mStatus_NoSuchNameErr, zd);
- }
- else
- {
- zd->CurrentSOA = (domainname *)(zd->CurrentSOA->c + zd->CurrentSOA->c[0]+1);
- AssignDomainName(&zd->question.qname, zd->CurrentSOA);
- GetZoneData_StartQuery(m, zd, kDNSType_SOA);
- }
+ zd->CurrentSOA = (domainname *)(zd->CurrentSOA->c + zd->CurrentSOA->c[0]+1);
+ AssignDomainName(&zd->question.qname, zd->CurrentSOA);
+ GetZoneData_StartQuery(m, zd, kDNSType_SOA);
}
else
{
@@ -1857,8 +1800,37 @@ mDNSlocal void GetZoneData_QuestionCallback(mDNS *const m, DNSQuestion *question
{
AssignDomainName(&zd->Host, &answer->rdata->u.srv.target);
zd->Port = answer->rdata->u.srv.port;
- AssignDomainName(&zd->question.qname, &zd->Host);
- GetZoneData_StartQuery(m, zd, kDNSType_A);
+ // The MakeTCPConn path, which is used by everything but DNS Push, won't work at all for
+ // IPv6. This should be fixed for all cases we care about, but for now we make an exception
+ // for Push notifications: we do not look up the a record here, but rather rely on the DSO
+ // infrastructure to do a GetAddrInfo call on the name and try each IP address in sequence
+ // until one connects. We can't do this for the other use cases because this is in the DSO
+ // code, not in MakeTCPConn. Ultimately the fix for this is to use Network Framework to do
+ // the connection establishment for all of these use cases.
+ //
+ // One implication of this is that if two different zones have DNS push server SRV records
+ // pointing to the same server using a different domain name, we will not see these as being
+ // the same server, and will not share the connection. This isn't something we can easily
+ // fix, and so the advice if someone runs into this and considers it a problem should be to
+ // use the same name.
+ //
+ // Another issue with this code is that at present, we do not wait for more than one SRV
+ // record--we cancel the query as soon as the first one comes in. This isn't ideal: it
+ // would be better to wait until we've gotten all our answers and then pick the one with
+ // the highest priority. Of course, this is unlikely to cause an operational problem in
+ // practice, and as with the previous point, the fix is easy: figure out which server you
+ // want people to use and don't list any other servers. Fully switching to Network
+ // Framework for this would (I think!) address this problem, or at least make it someone
+ // else's problem.
+ if (zd->ZoneService != ZoneServiceDNSPush)
+ {
+ AssignDomainName(&zd->question.qname, &zd->Host);
+ GetZoneData_StartQuery(m, zd, kDNSType_A);
+ }
+ else
+ {
+ zd->ZoneDataCallback(m, mStatus_NoError, zd);
+ }
}
else
{
@@ -1912,7 +1884,6 @@ mDNSlocal mStatus GetZoneData_StartQuery(mDNS *const m, ZoneData *zd, mDNSu16 qt
zd->question.ThisQInterval = -1;
zd->question.InterfaceID = mDNSInterface_Any;
zd->question.flags = 0;
- zd->question.Target = zeroAddr;
//zd->question.qname.c[0] = 0; // Already set
zd->question.qtype = qtype;
zd->question.qclass = kDNSClass_IN;
@@ -1921,17 +1892,11 @@ mDNSlocal mStatus GetZoneData_StartQuery(mDNS *const m, ZoneData *zd, mDNSu16 qt
zd->question.ForceMCast = mDNSfalse;
zd->question.ReturnIntermed = mDNStrue;
zd->question.SuppressUnusable = mDNSfalse;
- zd->question.SearchListIndex = 0;
zd->question.AppendSearchDomains = 0;
- zd->question.RetryWithSearchDomains = mDNSfalse;
zd->question.TimeoutQuestion = 0;
zd->question.WakeOnResolve = 0;
- zd->question.UseBackgroundTrafficClass = mDNSfalse;
- zd->question.ValidationRequired = 0;
- zd->question.ValidatingResponse = 0;
+ zd->question.UseBackgroundTraffic = mDNSfalse;
zd->question.ProxyQuestion = 0;
- zd->question.qnameOrig = mDNSNULL;
- zd->question.AnonInfo = mDNSNULL;
zd->question.pid = mDNSPlatformGetPID();
zd->question.euid = 0;
zd->question.QuestionCallback = GetZoneData_QuestionCallback;
@@ -1944,51 +1909,25 @@ mDNSlocal mStatus GetZoneData_StartQuery(mDNS *const m, ZoneData *zd, mDNSu16 qt
// StartGetZoneData is an internal routine (i.e. must be called with the lock already held)
mDNSexport ZoneData *StartGetZoneData(mDNS *const m, const domainname *const name, const ZoneService target, ZoneDataCallback callback, void *ZoneDataContext)
{
- DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, name);
- int initialskip = (AuthInfo && AuthInfo->AutoTunnel) ? DomainNameLength(name) - DomainNameLength(&AuthInfo->domain) : 0;
- ZoneData *zd = (ZoneData*)mDNSPlatformMemAllocate(sizeof(ZoneData));
- if (!zd) { LogMsg("ERROR: StartGetZoneData - mDNSPlatformMemAllocate failed"); return mDNSNULL; }
- mDNSPlatformMemZero(zd, sizeof(ZoneData));
+ ZoneData *zd = (ZoneData*) mDNSPlatformMemAllocateClear(sizeof(*zd));
+ if (!zd) { LogMsg("ERROR: StartGetZoneData - mDNSPlatformMemAllocateClear failed"); return mDNSNULL; }
AssignDomainName(&zd->ChildName, name);
zd->ZoneService = target;
- zd->CurrentSOA = (domainname *)(&zd->ChildName.c[initialskip]);
+ zd->CurrentSOA = &zd->ChildName;
zd->ZoneName.c[0] = 0;
zd->ZoneClass = 0;
zd->Host.c[0] = 0;
zd->Port = zeroIPPort;
zd->Addr = zeroAddr;
- zd->ZonePrivate = AuthInfo && AuthInfo->AutoTunnel ? mDNStrue : mDNSfalse;
+ zd->ZonePrivate = mDNSfalse;
zd->ZoneDataCallback = callback;
zd->ZoneDataContext = ZoneDataContext;
zd->question.QuestionContext = zd;
mDNS_DropLockBeforeCallback(); // GetZoneData_StartQuery expects to be called from a normal callback, so we emulate that here
- if (AuthInfo && AuthInfo->AutoTunnel && !mDNSIPPortIsZero(AuthInfo->port))
- {
- LogInfo("StartGetZoneData: Bypassing SOA, SRV query for %##s", AuthInfo->domain.c);
- // We bypass SOA and SRV queries if we know the hostname and port already from the configuration.
- // Today this is only true for AutoTunnel. As we bypass, we need to infer a few things:
- //
- // 1. Zone name is the same as the AuthInfo domain
- // 2. ZoneClass is kDNSClass_IN which should be a safe assumption
- //
- // If we want to make this bypass mechanism work for non-AutoTunnels also, (1) has to hold
- // good. Otherwise, it has to be configured also.
-
- AssignDomainName(&zd->ZoneName, &AuthInfo->domain);
- zd->ZoneClass = kDNSClass_IN;
- AssignDomainName(&zd->Host, &AuthInfo->hostname);
- zd->Port = AuthInfo->port;
- AssignDomainName(&zd->question.qname, &zd->Host);
- GetZoneData_StartQuery(m, zd, kDNSType_A);
- }
- else
- {
- if (AuthInfo && AuthInfo->AutoTunnel) LogInfo("StartGetZoneData: Not Bypassing SOA, SRV query for %##s", AuthInfo->domain.c);
- AssignDomainName(&zd->question.qname, zd->CurrentSOA);
- GetZoneData_StartQuery(m, zd, kDNSType_SOA);
- }
+ AssignDomainName(&zd->question.qname, zd->CurrentSOA);
+ GetZoneData_StartQuery(m, zd, kDNSType_SOA);
mDNS_ReclaimLockAfterCallback();
return zd;
@@ -2331,7 +2270,7 @@ mDNSlocal void UpdateOneSRVRecord(mDNS *m, AuthRecord *rr)
case regState_NATError:
if (!NATChanged) return;
- // if nat changed, register if we have a target (below)
+ // if nat changed, register if we have a target (below)
/* FALLTHROUGH */
case regState_NoTarget:
@@ -2602,7 +2541,6 @@ mDNSlocal void GetStaticHostname(mDNS *m)
q->InterfaceID = mDNSInterface_Any;
q->flags = 0;
- q->Target = zeroAddr;
q->qtype = kDNSType_PTR;
q->qclass = kDNSClass_IN;
q->LongLived = mDNSfalse;
@@ -2610,17 +2548,11 @@ mDNSlocal void GetStaticHostname(mDNS *m)
q->ForceMCast = mDNSfalse;
q->ReturnIntermed = mDNStrue;
q->SuppressUnusable = mDNSfalse;
- q->SearchListIndex = 0;
q->AppendSearchDomains = 0;
- q->RetryWithSearchDomains = mDNSfalse;
q->TimeoutQuestion = 0;
q->WakeOnResolve = 0;
- q->UseBackgroundTrafficClass = mDNSfalse;
- q->ValidationRequired = 0;
- q->ValidatingResponse = 0;
+ q->UseBackgroundTraffic = mDNSfalse;
q->ProxyQuestion = 0;
- q->qnameOrig = mDNSNULL;
- q->AnonInfo = mDNSNULL;
q->pid = mDNSPlatformGetPID();
q->euid = 0;
q->QuestionCallback = FoundStaticHostname;
@@ -2641,10 +2573,9 @@ mDNSexport void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSReco
if (*ptr) { LogMsg("DynDNSHostName %##s already in list", fqdn->c); return; }
// allocate and format new address record
- *ptr = mDNSPlatformMemAllocate(sizeof(**ptr));
+ *ptr = (HostnameInfo *) mDNSPlatformMemAllocateClear(sizeof(**ptr));
if (!*ptr) { LogMsg("ERROR: mDNS_AddDynDNSHostName - malloc"); return; }
- mDNSPlatformMemZero(*ptr, sizeof(**ptr));
AssignDomainName(&(*ptr)->fqdn, fqdn);
(*ptr)->arv4.state = regState_Unregistered;
(*ptr)->arv6.state = regState_Unregistered;
@@ -2786,10 +2717,6 @@ mDNSexport void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, co
m->StaticHostname.c[0] = 0;
m->NextSRVUpdate = NonZeroTime(m->timenow);
-
-#if APPLE_OSX_mDNSResponder
- UpdateAutoTunnelDomainStatuses(m);
-#endif
}
mDNS_Unlock(m);
@@ -2896,23 +2823,14 @@ mDNSlocal mStatus checkUpdateResult(mDNS *const m, const domainname *const displ
}
}
-// We add three Additional Records for unicast resource record registrations
-// which is a function of AuthInfo and AutoTunnel properties
-mDNSlocal mDNSu32 RRAdditionalSize(mDNS *const m, DomainAuthInfo *AuthInfo)
+mDNSlocal mDNSu32 RRAdditionalSize(DomainAuthInfo *AuthInfo)
{
- mDNSu32 leaseSize, hinfoSize, tsigSize;
+ mDNSu32 leaseSize, tsigSize;
mDNSu32 rr_base_size = 10; // type (2) class (2) TTL (4) rdlength (2)
// OPT RR : Emptyname(.) + base size + rdataOPT
leaseSize = 1 + rr_base_size + sizeof(rdataOPT);
- // HINFO: Resource Record Name + base size + RDATA
- // HINFO is added only for autotunnels
- hinfoSize = 0;
- if (AuthInfo && AuthInfo->AutoTunnel)
- hinfoSize = (m->hostlabel.c[0] + 1) + DomainNameLength(&AuthInfo->domain) +
- rr_base_size + (2 + m->HIHardware.c[0] + m->HISoftware.c[0]);
-
//TSIG: Resource Record Name + base size + RDATA
// RDATA:
// Algorithm name: hmac-md5.sig-alg.reg.int (8+7+3+3 + 5 bytes for length = 26 bytes)
@@ -2927,7 +2845,7 @@ mDNSlocal mDNSu32 RRAdditionalSize(mDNS *const m, DomainAuthInfo *AuthInfo)
tsigSize = 0;
if (AuthInfo) tsigSize = DomainNameLength(&AuthInfo->keyname) + rr_base_size + 58;
- return (leaseSize + hinfoSize + tsigSize);
+ return (leaseSize + tsigSize);
}
//Note: Make sure that RREstimatedSize is updated accordingly if anything that is done here
@@ -3009,7 +2927,7 @@ mDNSlocal void SendRecordRegistration(mDNS *const m, AuthRecord *rr)
limit = ptr + AbsoluteMaxDNSMessageData;
AuthInfo = GetAuthInfoForName_internal(m, rr->resrec.name);
- limit -= RRAdditionalSize(m, AuthInfo);
+ limit -= RRAdditionalSize(AuthInfo);
mDNS_CheckLock(m);
@@ -3046,7 +2964,7 @@ mDNSlocal void SendRecordRegistration(mDNS *const m, AuthRecord *rr)
{
LogInfo("SendRecordRegistration UDP %s", ARDisplayString(m, rr));
if (!rr->nta) { LogMsg("SendRecordRegistration:ERROR!! nta is NULL for %s", ARDisplayString(m, rr)); return; }
- err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &rr->nta->Addr, rr->nta->Port, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name), mDNSfalse);
+ err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, mDNSNULL, &rr->nta->Addr, rr->nta->Port, GetAuthInfoForName_internal(m, rr->resrec.name), mDNSfalse);
if (err) debugf("ERROR: SendRecordRegistration - mDNSSendDNSMessage - %d", err);
}
@@ -3139,8 +3057,7 @@ mDNSlocal void SendGroupRRMessage(mDNS *const m, AuthRecord *anchorRR, mDNSu8 *p
mDNSu8 *limit;
if (!anchorRR) {debugf("SendGroupRRMessage: Could not merge records"); return;}
- if (info && info->AutoTunnel) limit = m->omsg.data + AbsoluteMaxDNSMessageData;
- else limit = m->omsg.data + NormalMaxDNSMessageData;
+ limit = m->omsg.data + NormalMaxDNSMessageData;
// This has to go in the additional section and hence need to be done last
ptr = putUpdateLeaseWithLimit(&m->omsg, ptr, DEFAULT_UPDATE_LEASE, limit);
@@ -3162,7 +3079,7 @@ mDNSlocal void SendGroupRRMessage(mDNS *const m, AuthRecord *anchorRR, mDNSu8 *p
}
else
{
- mStatus err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &anchorRR->nta->Addr, anchorRR->nta->Port, mDNSNULL, info, mDNSfalse);
+ mStatus err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, mDNSNULL, &anchorRR->nta->Addr, anchorRR->nta->Port, info, mDNSfalse);
if (err) LogInfo("SendGroupRRMessage: Cannot send UDP message for %s", ARDisplayString(m, anchorRR));
else LogInfo("SendGroupRRMessage: Sent a group UDP update ID: %d start %p, end %p, limit %p", mDNSVal16(m->omsg.h.id), m->omsg.data, ptr, limit);
}
@@ -3318,11 +3235,10 @@ mDNSlocal mDNSBool SendGroupUpdates(mDNS *const m)
// Though we allow single record registrations for UDP to be AbsoluteMaxDNSMessageData (See
// SendRecordRegistration) to handle large TXT records, to avoid fragmentation we limit UDP
// message to NormalMaxDNSMessageData
- if (AuthInfo && AuthInfo->AutoTunnel) spaceleft = AbsoluteMaxDNSMessageData;
- else spaceleft = NormalMaxDNSMessageData;
+ spaceleft = NormalMaxDNSMessageData;
next = m->omsg.data;
- spaceleft -= RRAdditionalSize(m, AuthInfo);
+ spaceleft -= RRAdditionalSize(AuthInfo);
if (spaceleft <= 0)
{
LogMsg("SendGroupUpdates: ERROR!!: spaceleft is zero at the beginning");
@@ -3525,9 +3441,6 @@ mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err, mDNSu
LogInfo("hndlRecordUpdateReply: err %d ID %d state %d %s(%p)", err, mDNSVal16(rr->updateid), rr->state, ARDisplayString(m, rr), rr);
rr->updateError = err;
-#if APPLE_OSX_mDNSResponder
- if (err == mStatus_BadSig || err == mStatus_BadKey || err == mStatus_BadTime) UpdateAutoTunnelDomainStatuses(m);
-#endif
SetRecordRetry(m, rr, random);
@@ -3920,7 +3833,7 @@ mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNS
msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,",
msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y, " : "ies,",
msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s", end - msg->data);
-#if APPLE_OSX_mDNSResponder
+#if MDNSRESPONDER_SUPPORTS(APPLE, SYMPTOMS) && !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
if (NumUnreachableDNSServers > 0)
SymptomReporterDNSServerReachable(m, srcaddr);
#endif
@@ -3932,7 +3845,13 @@ mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNS
if (msg->h.flags.b[0] & kDNSFlag0_TC && mDNSSameOpaque16(qptr->TargetQID, msg->h.id) && m->timenow - qptr->LastQTime < RESPONSE_WINDOW)
{
if (!srcaddr) LogMsg("uDNS_ReceiveMsg: TCP DNS response had TC bit set: ignoring");
- else uDNS_RestartQuestionAsTCP(m, qptr, srcaddr, srcport);
+ else
+ {
+ uDNS_RestartQuestionAsTCP(m, qptr, srcaddr, srcport);
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
+ qptr->metrics.dnsOverTCPState = DNSOverTCP_Truncated;
+#endif
+ }
}
}
@@ -3982,7 +3901,6 @@ mDNSexport void sendLLQRefresh(mDNS *m, DNSQuestion *q)
{
mDNSu8 *end;
LLQOptData llq;
- mDNSu8 *limit = m->omsg.data + AbsoluteMaxDNSMessageData;
if (q->ReqLease)
if ((q->state == LLQ_Established && q->ntries >= kLLQ_MAX_TRIES) || q->expire - m->timenow < 0)
@@ -4002,45 +3920,12 @@ mDNSexport void sendLLQRefresh(mDNS *m, DNSQuestion *q)
end = putLLQ(&m->omsg, m->omsg.data, q, &llq);
if (!end) { LogMsg("sendLLQRefresh: putLLQ failed %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return; }
- // Note that we (conditionally) add HINFO and TSIG here, since the question might be going away,
- // so we may not be able to reference it (most importantly it's AuthInfo) when we actually send the message
- end = putHINFO(m, &m->omsg, end, q->AuthInfo, limit);
- if (!end) { LogMsg("sendLLQRefresh: putHINFO failed %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return; }
-
- if (PrivateQuery(q))
- {
- DNSDigest_SignMessageHostByteOrder(&m->omsg, &end, q->AuthInfo);
- if (!end) { LogMsg("sendLLQRefresh: DNSDigest_SignMessage failed %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return; }
- }
-
- if (PrivateQuery(q) && !q->tcp)
- {
- LogInfo("sendLLQRefresh setting up new TLS session %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- if (!q->nta)
- {
- // Note: If a question is in LLQ_Established state, we never free the zone data for the
- // question (PrivateQuery). If we free, we reset the state to something other than LLQ_Established.
- // This function is called only if the query is in LLQ_Established state and hence nta should
- // never be NULL. In spite of that, we have seen q->nta being NULL in the field. Just refetch the
- // zone data in that case.
- q->nta = StartGetZoneData(m, &q->qname, ZoneServiceLLQ, LLQGotZoneData, q);
- return;
- // ThisQInterval is not adjusted when we return from here which means that we will get called back
- // again immediately. As q->servAddr and q->servPort are still valid and the nta->Host is initialized
- // without any additional discovery for PrivateQuery, things work.
- }
- q->tcp = MakeTCPConn(m, &m->omsg, end, kTCPSocketFlags_UseTLS, &q->servAddr, q->servPort, &q->nta->Host, q, mDNSNULL);
- }
- else
{
mStatus err;
- // if AuthInfo and AuthInfo->AutoTunnel is set, we use the TCP socket but don't need to pass the AuthInfo as
- // we already protected the message above.
- LogInfo("sendLLQRefresh: using existing %s session %##s (%s)", PrivateQuery(q) ? "TLS" : "UDP",
- q->qname.c, DNSTypeName(q->qtype));
+ LogInfo("sendLLQRefresh: using existing UDP session %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- err = mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, q->LocalSocket, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, mDNSNULL, mDNSfalse);
+ err = mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, q->tcp ? q->tcp->sock : mDNSNULL, q->LocalSocket, &q->servAddr, q->servPort, mDNSNULL, mDNSfalse);
if (err)
{
LogMsg("sendLLQRefresh: mDNSSendDNSMessage%s failed: %d", q->tcp ? " (TCP)" : "", err);
@@ -4072,16 +3957,13 @@ mDNSexport void LLQGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneI
{
q->servAddr = zoneInfo->Addr;
q->servPort = zoneInfo->Port;
- if (!PrivateQuery(q))
+ // We don't need the zone data as we use it only for the Host information which we
+ // don't need if we are not going to use TLS connections.
+ if (q->nta)
{
- // We don't need the zone data as we use it only for the Host information which we
- // don't need if we are not going to use TLS connections.
- if (q->nta)
- {
- if (q->nta != zoneInfo) LogMsg("LLQGotZoneData: nta (%p) != zoneInfo (%p) %##s (%s)", q->nta, zoneInfo, q->qname.c, DNSTypeName(q->qtype));
- CancelGetZoneData(m, q->nta);
- q->nta = mDNSNULL;
- }
+ if (q->nta != zoneInfo) LogMsg("LLQGotZoneData: nta (%p) != zoneInfo (%p) %##s (%s)", q->nta, zoneInfo, q->qname.c, DNSTypeName(q->qtype));
+ CancelGetZoneData(m, q->nta);
+ q->nta = mDNSNULL;
}
q->ntries = 0;
debugf("LLQGotZoneData %#a:%d", &q->servAddr, mDNSVal16(q->servPort));
@@ -4107,90 +3989,36 @@ mDNSexport void LLQGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneI
mDNS_Unlock(m);
}
-#ifdef DNS_PUSH_ENABLED
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
mDNSexport void DNSPushNotificationGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneInfo)
{
DNSQuestion *q = (DNSQuestion *)zoneInfo->ZoneDataContext;
mDNS_Lock(m);
// If we get here it means that the GetZoneData operation has completed.
- // We hold on to the zone data if it is AutoTunnel as we use the hostname
- // in zoneInfo during the TLS connection setup.
q->servAddr = zeroAddr;
q->servPort = zeroIPPort;
- if (!err && zoneInfo && !mDNSIPPortIsZero(zoneInfo->Port) && !mDNSAddressIsZero(&zoneInfo->Addr) && zoneInfo->Host.c[0])
- {
- q->dnsPushState = DNSPUSH_SERVERFOUND;
- q->dnsPushServerAddr = zoneInfo->Addr;
- q->dnsPushServerPort = zoneInfo->Port;
- q->ntries = 0;
- LogInfo("DNSPushNotificationGotZoneData %#a:%d", &q->dnsPushServerAddr, mDNSVal16(q->dnsPushServerPort));
- SubscribeToDNSPushNotificationServer(m,q);
- }
- else
+ if (!err && zoneInfo && !mDNSIPPortIsZero(zoneInfo->Port) && zoneInfo->Host.c[0])
{
- q->dnsPushState = DNSPUSH_NOSERVER;
- StartLLQPolling(m,q);
- if (err == mStatus_NoSuchNameErr)
+ q->state = LLQ_DNSPush_Connecting;
+ LogInfo("DNSPushNotificationGotZoneData %##s%%%d", &zoneInfo->Host, ntohs(zoneInfo->Port.NotAnInteger));
+ q->dnsPushServer = SubscribeToDNSPushNotificationServer(m, q);
+ if (q->dnsPushServer == mDNSNULL || (q->dnsPushServer->connectState != DNSPushServerConnectionInProgress &&
+ q->dnsPushServer->connectState != DNSPushServerConnected &&
+ q->dnsPushServer->connectState != DNSPushServerSessionEstablished))
{
- // this actually failed, so mark it by setting address to all ones
- q->servAddr.type = mDNSAddrType_IPv4;
- q->servAddr.ip.v4 = onesIPv4Addr;
+ goto noServer;
}
}
- mDNS_Unlock(m);
-}
-#endif // DNS_PUSH_ENABLED
-
-// Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1)
-mDNSlocal void PrivateQueryGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneInfo)
-{
- DNSQuestion *q = (DNSQuestion *) zoneInfo->ZoneDataContext;
-
- LogInfo("PrivateQueryGotZoneData %##s (%s) err %d Zone %##s Private %d", q->qname.c, DNSTypeName(q->qtype), err, zoneInfo->ZoneName.c, zoneInfo->ZonePrivate);
-
- if (q->nta != zoneInfo) LogMsg("PrivateQueryGotZoneData:ERROR!!: nta (%p) != zoneInfo (%p) %##s (%s)", q->nta, zoneInfo, q->qname.c, DNSTypeName(q->qtype));
-
- if (err || !zoneInfo || mDNSAddressIsZero(&zoneInfo->Addr) || mDNSIPPortIsZero(zoneInfo->Port) || !zoneInfo->Host.c[0])
- {
- LogInfo("PrivateQueryGotZoneData: ERROR!! %##s (%s) invoked with error code %d %p %#a:%d",
- q->qname.c, DNSTypeName(q->qtype), err, zoneInfo,
- zoneInfo ? &zoneInfo->Addr : mDNSNULL,
- zoneInfo ? mDNSVal16(zoneInfo->Port) : 0);
- CancelGetZoneData(m, q->nta);
- q->nta = mDNSNULL;
- return;
- }
-
- if (!zoneInfo->ZonePrivate)
- {
- debugf("Private port lookup failed -- retrying without TLS -- %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- q->AuthInfo = mDNSNULL; // Clear AuthInfo so we try again non-private
- q->ThisQInterval = InitialQuestionInterval;
- q->LastQTime = m->timenow - q->ThisQInterval;
- CancelGetZoneData(m, q->nta);
- q->nta = mDNSNULL;
- mDNS_Lock(m);
- SetNextQueryTime(m, q);
- mDNS_Unlock(m);
- return;
- // Next call to uDNS_CheckCurrentQuestion() will do this as a non-private query
- }
-
- if (!PrivateQuery(q))
+ else
{
- LogMsg("PrivateQueryGotZoneData: ERROR!! Not a private query %##s (%s) AuthInfo %p", q->qname.c, DNSTypeName(q->qtype), q->AuthInfo);
- CancelGetZoneData(m, q->nta);
- q->nta = mDNSNULL;
- return;
+ noServer:
+ q->state = LLQ_InitialRequest;
+ startLLQHandshake(m,q);
}
-
- q->TargetQID = mDNS_NewMessageID(m);
- if (q->tcp) { DisposeTCPConn(q->tcp); q->tcp = mDNSNULL; }
- if (!q->nta) { LogMsg("PrivateQueryGotZoneData:ERROR!! nta is NULL for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return; }
- q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &zoneInfo->Addr, zoneInfo->Port, &q->nta->Host, q, mDNSNULL);
- if (q->nta) { CancelGetZoneData(m, q->nta); q->nta = mDNSNULL; }
+ mDNS_Unlock(m);
}
+#endif
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
@@ -4320,19 +4148,6 @@ mDNSexport void RecordRegistrationGotZoneData(mDNS *const m, mStatus err, const
mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) && newRR->nta && !mDNSAddrIsRFC1918(&newRR->nta->Addr) &&
newRR->AutoTarget == Target_AutoHostAndNATMAP)
{
- DomainAuthInfo *AuthInfo;
- AuthInfo = GetAuthInfoForName(m, newRR->resrec.name);
- if (AuthInfo && AuthInfo->AutoTunnel)
- {
- domainname *t = GetRRDomainNameTarget(&newRR->resrec);
- LogMsg("RecordRegistrationGotZoneData: ERROR!! AutoTunnel has Target_AutoHostAndNATMAP for %s", ARDisplayString(m, newRR));
- if (t) t->c[0] = 0;
- newRR->resrec.rdlength = newRR->resrec.rdestimate = 0;
- newRR->state = regState_NoTarget;
- CancelGetZoneData(m, newRR->nta);
- newRR->nta = mDNSNULL;
- return;
- }
// During network transitions, we are called multiple times in different states. Setup NAT
// state just once for this record.
if (!newRR->NATinfo.clientContext)
@@ -4381,7 +4196,7 @@ mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr)
limit = ptr + AbsoluteMaxDNSMessageData;
AuthInfo = GetAuthInfoForName_internal(m, rr->resrec.name);
- limit -= RRAdditionalSize(m, AuthInfo);
+ limit -= RRAdditionalSize(AuthInfo);
rr->updateid = mDNS_NewMessageID(m);
InitializeDNSMessage(&m->omsg.h, rr->updateid, UpdateReqFlags);
@@ -4407,7 +4222,7 @@ mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr)
mStatus err;
LogInfo("SendRecordDeregistration UDP %s", ARDisplayString(m, rr));
if (!rr->nta) { LogMsg("SendRecordDeregistration:ERROR!! nta is NULL for %s", ARDisplayString(m, rr)); return; }
- err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &rr->nta->Addr, rr->nta->Port, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name), mDNSfalse);
+ err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, mDNSNULL, &rr->nta->Addr, rr->nta->Port, GetAuthInfoForName_internal(m, rr->resrec.name), mDNSfalse);
if (err) debugf("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %d", err);
//if (rr->state == regState_DeregPending) CompleteDeregistration(m, rr); // Don't touch rr after this
}
@@ -4602,70 +4417,76 @@ unreg_error:
#pragma mark - Periodic Execution Routines
#endif
-mDNSlocal void handle_unanswered_query(mDNS *const m)
+mDNSlocal void uDNS_HandleLLQState(mDNS *const m, DNSQuestion *q)
{
- DNSQuestion *q = m->CurrentQuestion;
-
- if (q->unansweredQueries >= MAX_DNSSEC_UNANSWERED_QUERIES && DNSSECOptionalQuestion(q))
+ LogMsg("->uDNS_HandleLLQState: %##s %d", &q->qname, q->state);
+ switch(q->state)
{
- // If we are not receiving any responses for DNSSEC question, it could be due to
- // a broken middlebox or a DNS server that does not understand the EDNS0/DOK option that
- // silently drops the packets. Also as per RFC 5625 there are certain buggy DNS Proxies
- // that are known to drop these pkts. To handle this, we turn off sending the EDNS0/DOK
- // option if we have not received any responses indicating that the server or
- // the middlebox is DNSSEC aware. If we receive at least one response to a DNSSEC
- // question, we don't turn off validation. Also, we wait for MAX_DNSSEC_RETRANSMISSIONS
- // before turning off validation to accomodate packet loss.
- //
- // Note: req_DO affects only DNSSEC_VALIDATION_SECURE_OPTIONAL questions;
- // DNSSEC_VALIDATION_SECURE questions ignores req_DO.
+ case LLQ_Init:
+ // If DNS Push isn't supported, LLQ_Init falls through to LLQ_InitialRequest.
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
+ // First attempt to use DNS Push Notification.
+ DiscoverDNSPushNotificationServer(m, q);
+ break;
- if (!q->qDNSServer->DNSSECAware && q->qDNSServer->req_DO)
+ case LLQ_DNSPush_ServerDiscovery:
+ case LLQ_DNSPush_Connecting:
+ case LLQ_DNSPush_Established:
+ // Sanity check the server state to see if it matches. If we find that we aren't connected, when
+ // we think we should be, change our state.
+ if (q->dnsPushServer == NULL)
{
- q->qDNSServer->retransDO++;
- if (q->qDNSServer->retransDO == MAX_DNSSEC_RETRANSMISSIONS)
- {
- LogInfo("handle_unanswered_query: setting req_DO false for %#a", &q->qDNSServer->addr);
- q->qDNSServer->req_DO = mDNSfalse;
- }
+ q->state = LLQ_Init;
+ q->ThisQInterval = 0;
+ q->LastQTime = m->timenow;
+ SetNextQueryTime(m, q);
}
-
- if (!q->qDNSServer->req_DO)
+ else
{
- q->ValidationState = DNSSECValNotRequired;
- q->ValidationRequired = DNSSEC_VALIDATION_NONE;
-
- if (q->ProxyQuestion)
- q->ProxyDNSSECOK = mDNSfalse;
- LogInfo("handle_unanswered_query: unanswered query for %##s (%s), so turned off validation for %#a",
- q->qname.c, DNSTypeName(q->qtype), &q->qDNSServer->addr);
+ switch(q->dnsPushServer->connectState)
+ {
+ case DNSPushServerDisconnected:
+ case DNSPushServerConnectFailed:
+ case DNSPushServerNoDNSPush:
+ LogMsg("uDNS_HandleLLQState: %##s, server state %d doesn't match question state %d",
+ &q->dnsPushServer->serverName, q->state, q->dnsPushServer->connectState);
+ q->state = LLQ_Poll;
+ q->ThisQInterval = (mDNSPlatformOneSecond * 5);
+ q->LastQTime = m->timenow;
+ SetNextQueryTime(m, q);
+ break;
+ case DNSPushServerSessionEstablished:
+ LogMsg("uDNS_HandleLLQState: %##s, server connection established but question state is %d",
+ &q->dnsPushServer->serverName, q->state);
+ q->state = LLQ_DNSPush_Established;
+ q->ThisQInterval = 0;
+ q->LastQTime = m->timenow;
+ SetNextQueryTime(m, q);
+ break;
+
+ case DNSPushServerConnectionInProgress:
+ case DNSPushServerConnected:
+ break;
+ }
}
- }
-}
-
-mDNSlocal void uDNS_HandleLLQState(mDNS *const m, DNSQuestion *q)
-{
-#ifdef DNS_PUSH_ENABLED
- // First attempt to use DNS Push Notification.
- if (q->dnsPushState == DNSPUSH_INIT)
- DiscoverDNSPushNotificationServer(m, q);
-#endif // DNS_PUSH_ENABLED
- switch (q->state)
- {
+ break;
+#else
+ // Silence warnings; these are never reached without DNS Push
+ case LLQ_DNSPush_ServerDiscovery:
+ case LLQ_DNSPush_Connecting:
+ case LLQ_DNSPush_Established:
+#endif // MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
case LLQ_InitialRequest: startLLQHandshake(m, q); break;
- case LLQ_SecondaryRequest:
- // For PrivateQueries, we need to start the handshake again as we don't do the Challenge/Response step
- if (PrivateQuery(q)) startLLQHandshake(m, q);
- else sendChallengeResponse(m, q, mDNSNULL);
- break;
+ case LLQ_SecondaryRequest: sendChallengeResponse(m, q, mDNSNULL); break;
case LLQ_Established: sendLLQRefresh(m, q); break;
case LLQ_Poll: break; // Do nothing (handled below)
}
+ LogMsg("<-uDNS_HandleLLQState: %##s %d %d", &q->qname, q->state);
}
// The question to be checked is not passed in as an explicit parameter;
// instead it is implicit that the question to be checked is m->CurrentQuestion.
-mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
+mDNSlocal void uDNS_CheckCurrentQuestion(mDNS *const m)
{
DNSQuestion *q = m->CurrentQuestion;
if (m->timenow - NextQSendTime(q) < 0) return;
@@ -4675,7 +4496,9 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
uDNS_HandleLLQState(m,q);
}
- handle_unanswered_query(m);
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ Querier_HandleUnicastQuestion(q);
+#else
// We repeat the check above (rather than just making this the "else" case) because startLLQHandshake can change q->state to LLQ_Poll
if (!(q->LongLived && q->state != LLQ_Poll))
{
@@ -4683,10 +4506,13 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
{
DNSServer *orig = q->qDNSServer;
if (orig)
- LogInfo("uDNS_CheckCurrentQuestion: Sent %d unanswered queries for %##s (%s) to %#a:%d (%##s)",
- q->unansweredQueries, q->qname.c, DNSTypeName(q->qtype), &orig->addr, mDNSVal16(orig->port), orig->domain.c);
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] uDNS_CheckCurrentQuestion: Sent %d unanswered queries for " PRI_DM_NAME " (" PUB_S ") to " PRI_IP_ADDR ":%d (" PRI_DM_NAME ")",
+ q->request_id, mDNSVal16(q->TargetQID), q->unansweredQueries, DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype), &orig->addr, mDNSVal16(orig->port), DM_NAME_PARAM(&orig->domain));
+ }
-#if APPLE_OSX_mDNSResponder
+#if MDNSRESPONDER_SUPPORTS(APPLE, SYMPTOMS)
SymptomReporterDNSServerUnreachable(orig);
#endif
PenalizeDNSServer(m, q, zeroID);
@@ -4709,16 +4535,16 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
{
DNSServer *new;
DNSQuestion *qptr;
- q->triedAllServersOnce = 1;
+ q->triedAllServersOnce = mDNStrue;
// Re-initialize all DNS servers for this question. If we have a DNSServer, DNSServerChangeForQuestion will
// handle all the work including setting the new DNS server.
SetValidDNSServers(m, q);
new = GetServerForQuestion(m, q);
if (new)
{
- mDNSIPPort zp = zeroIPPort;
- LogInfo("uDNS_checkCurrentQuestion: Retrying question %p %##s (%s) DNS Server %#a:%d ThisQInterval %d",
- q, q->qname.c, DNSTypeName(q->qtype), new ? &new->addr : mDNSNULL, mDNSVal16(new? new->port : zp), q->ThisQInterval);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] uDNS_checkCurrentQuestion: Retrying question %p " PRI_DM_NAME " (" PUB_S ") DNS Server " PRI_IP_ADDR ":%d ThisQInterval %d",
+ q->request_id, mDNSVal16(q->TargetQID), q, DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype), new ? &new->addr : mDNSNULL, mDNSVal16(new ? new->port : zeroIPPort), q->ThisQInterval);
DNSServerChangeForQuestion(m, q, new);
}
for (qptr = q->next ; qptr; qptr = qptr->next)
@@ -4728,84 +4554,66 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
{
mDNSu8 *end;
mStatus err = mStatus_NoError;
- mDNSBool private = mDNSfalse;
-
- InitializeDNSMessage(&m->omsg.h, q->TargetQID, (DNSSECQuestion(q) ? DNSSecQFlags : uQueryFlags));
+ mDNSOpaque16 HeaderFlags = uQueryFlags;
+ InitializeDNSMessage(&m->omsg.h, q->TargetQID, HeaderFlags);
end = putQuestion(&m->omsg, m->omsg.data, m->omsg.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
- if (DNSSECQuestion(q) && !q->qDNSServer->cellIntf)
- {
- if (q->ProxyQuestion)
- end = DNSProxySetAttributes(q, &m->omsg.h, &m->omsg, end, m->omsg.data + AbsoluteMaxDNSMessageData);
- else
- end = putDNSSECOption(&m->omsg, end, m->omsg.data + AbsoluteMaxDNSMessageData);
- }
- private = PrivateQuery(q);
if (end > m->omsg.data)
{
- //LogMsg("uDNS_CheckCurrentQuestion %p %d %p %##s (%s)", q, NextQSendTime(q) - m->timenow, private, q->qname.c, DNSTypeName(q->qtype));
- if (private)
+ debugf("uDNS_CheckCurrentQuestion sending %p %##s (%s) %#a:%d UnansweredQueries %d",
+ q, q->qname.c, DNSTypeName(q->qtype),
+ q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL, mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort), q->unansweredQueries);
+#if APPLE_OSX_mDNSResponder
+ // When a DNS proxy network extension initiates the close of a UDP flow (this usually happens when a DNS
+ // proxy gets disabled or crashes), mDNSResponder's corresponding UDP socket will be marked with the
+ // SS_CANTRCVMORE state flag. Reading from such a socket is no longer possible, so close the current
+ // socket pair so that we can create a new pair.
+ if (q->LocalSocket && mDNSPlatformUDPSocketEncounteredEOF(q->LocalSocket))
{
- if (q->nta) CancelGetZoneData(m, q->nta);
- q->nta = StartGetZoneData(m, &q->qname, q->LongLived ? ZoneServiceLLQ : ZoneServiceQuery, PrivateQueryGotZoneData, q);
- if (q->state == LLQ_Poll) q->ThisQInterval = (LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10)) / QuestionIntervalStep;
+ mDNSPlatformUDPClose(q->LocalSocket);
+ q->LocalSocket = mDNSNULL;
}
- else
+#endif
+ if (!q->LocalSocket)
{
- mDNSIPPort zp = zeroIPPort;
- debugf("uDNS_CheckCurrentQuestion sending %p %##s (%s) %#a:%d UnansweredQueries %d",
- q, q->qname.c, DNSTypeName(q->qtype),
- q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL, mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort), q->unansweredQueries);
-#if APPLE_OSX_mDNSResponder
- // When a DNS proxy network extension initiates the close of a UDP flow (this usually happens when a DNS
- // proxy gets disabled or crashes), mDNSResponder's corresponding UDP socket will be marked with the
- // SS_CANTRCVMORE state flag. Reading from such a socket is no longer possible, so close the current
- // socket pair so that we can create a new pair.
- if (q->LocalSocket && mDNSPlatformUDPSocketEncounteredEOF(q->LocalSocket))
+ q->LocalSocket = mDNSPlatformUDPSocket(zeroIPPort);
+ if (q->LocalSocket)
{
- mDNSPlatformUDPClose(q->LocalSocket);
- q->LocalSocket = mDNSNULL;
+ mDNSPlatformSetSocktOpt(q->LocalSocket, mDNSTransport_UDP, mDNSAddrType_IPv4, q);
+ mDNSPlatformSetSocktOpt(q->LocalSocket, mDNSTransport_UDP, mDNSAddrType_IPv6, q);
}
-#endif
- if (!q->LocalSocket)
+ }
+ if (!q->LocalSocket) err = mStatus_NoMemoryErr; // If failed to make socket (should be very rare), we'll try again next time
+ else
+ {
+ err = mDNSSendDNSMessage(m, &m->omsg, end, q->qDNSServer->interface, mDNSNULL, q->LocalSocket, &q->qDNSServer->addr, q->qDNSServer->port, mDNSNULL, q->UseBackgroundTraffic);
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
+ if (!err)
{
- q->LocalSocket = mDNSPlatformUDPSocket(zeroIPPort);
- if (q->LocalSocket)
+ MetricsUpdateDNSQuerySize((mDNSu32)(end - (mDNSu8 *)&m->omsg));
+ if (q->metrics.answered)
{
- mDNSPlatformSetSocktOpt(q->LocalSocket, mDNSTransport_UDP, mDNSAddrType_IPv4, q);
- mDNSPlatformSetSocktOpt(q->LocalSocket, mDNSTransport_UDP, mDNSAddrType_IPv6, q);
+ q->metrics.querySendCount = 0;
+ q->metrics.answered = mDNSfalse;
}
- }
- if (!q->LocalSocket) err = mStatus_NoMemoryErr; // If failed to make socket (should be very rare), we'll try again next time
- else
- {
- err = mDNSSendDNSMessage(m, &m->omsg, end, q->qDNSServer->interface, q->LocalSocket, &q->qDNSServer->addr, q->qDNSServer->port, mDNSNULL, mDNSNULL, q->UseBackgroundTrafficClass);
-#if AWD_METRICS
- if (!err)
+ if (q->metrics.querySendCount++ == 0)
{
- MetricsUpdateDNSQuerySize((mDNSu32)(end - (mDNSu8 *)&m->omsg));
- if (q->metrics.answered)
- {
- q->metrics.querySendCount = 0;
- q->metrics.answered = mDNSfalse;
- }
- if (q->metrics.querySendCount++ == 0)
- {
- q->metrics.firstQueryTime = m->timenow;
- }
+ q->metrics.firstQueryTime = NonZeroTime(m->timenow);
}
-#endif
}
- }
+#endif
+ }
}
if (err == mStatus_HostUnreachErr)
{
DNSServer *newServer;
- LogInfo("uDNS_CheckCurrentQuestion: host unreachable error for DNS server %#a for question [%p] %##s (%s)",
- &q->qDNSServer->addr, q, q->qname.c, DNSTypeName(q->qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] uDNS_CheckCurrentQuestion: host unreachable error for DNS server " PRI_IP_ADDR " for question [%p] " PRI_DM_NAME " (" PUB_S ")",
+ q->request_id, mDNSVal16(q->TargetQID), &q->qDNSServer->addr, q, DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype));
if (!StrictUnicastOrdering)
{
@@ -4815,14 +4623,16 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
newServer = GetServerForQuestion(m, q);
if (!newServer)
{
- q->triedAllServersOnce = 1;
+ q->triedAllServersOnce = mDNStrue;
SetValidDNSServers(m, q);
newServer = GetServerForQuestion(m, q);
}
if (newServer)
{
- LogInfo("uDNS_checkCurrentQuestion: Retrying question %p %##s (%s) DNS Server %#a:%u ThisQInterval %d",
- q, q->qname.c, DNSTypeName(q->qtype), newServer ? &newServer->addr : mDNSNULL, mDNSVal16(newServer ? newServer->port : zeroIPPort), q->ThisQInterval);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] uDNS_checkCurrentQuestion: Retrying question %p " PRI_DM_NAME " (" PUB_S ") DNS Server " PRI_IP_ADDR ":%u ThisQInterval %d",
+ q->request_id, mDNSVal16(q->TargetQID), q, DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype),
+ newServer ? &newServer->addr : mDNSNULL, mDNSVal16(newServer ? newServer->port : zeroIPPort), q->ThisQInterval);
DNSServerChangeForQuestion(m, q, newServer);
}
if (q->triedAllServersOnce)
@@ -4850,24 +4660,14 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
q->unansweredQueries++;
if (q->ThisQInterval > MAX_UCAST_POLL_INTERVAL)
q->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
- if (private && q->state != LLQ_Poll)
- {
- // We don't want to retransmit too soon. Hence, we always schedule our first
- // retransmisson at 3 seconds rather than one second
- if (q->ThisQInterval < (3 * mDNSPlatformOneSecond))
- q->ThisQInterval = q->ThisQInterval * QuestionIntervalStep;
- if (q->ThisQInterval > LLQ_POLL_INTERVAL)
- q->ThisQInterval = LLQ_POLL_INTERVAL;
- LogInfo("uDNS_CheckCurrentQuestion: private non polling question for %##s (%s) will be retried in %d ms", q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval);
- }
- if (q->qDNSServer->cellIntf)
+ if (q->qDNSServer->isCell)
{
// We don't want to retransmit too soon. Schedule our first retransmisson at
// MIN_UCAST_RETRANS_TIMEOUT seconds.
if (q->ThisQInterval < MIN_UCAST_RETRANS_TIMEOUT)
q->ThisQInterval = MIN_UCAST_RETRANS_TIMEOUT;
}
- debugf("uDNS_CheckCurrentQuestion: Increased ThisQInterval to %d for %##s (%s), cell %d", q->ThisQInterval, q->qname.c, DNSTypeName(q->qtype), q->qDNSServer->cellIntf);
+ debugf("uDNS_CheckCurrentQuestion: Increased ThisQInterval to %d for %##s (%s), cell %d", q->ThisQInterval, q->qname.c, DNSTypeName(q->qtype), q->qDNSServer->isCell);
}
q->LastQTime = m->timenow;
}
@@ -4883,15 +4683,16 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
// (When we have a group of identical questions, only the active representative of the group gets
// passed to uDNS_CheckCurrentQuestion -- we only want one set of query packets hitting the wire --
// but we want *all* of the questions to get answer callbacks.)
- CacheRecord *rr;
+ CacheRecord *cr;
const mDNSu32 slot = HashSlotFromNameHash(q->qnamehash);
CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname);
if (!q->qDNSServer)
{
if (!mDNSOpaque128IsZero(&q->validDNSServers))
- LogMsg("uDNS_CheckCurrentQuestion: ERROR!!: valid DNSServer bits not zero 0x%x, 0x%x 0x%x 0x%x for question %##s (%s)",
- q->validDNSServers.l[3], q->validDNSServers.l[2], q->validDNSServers.l[1], q->validDNSServers.l[0], q->qname.c, DNSTypeName(q->qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[R%u->Q%u] uDNS_CheckCurrentQuestion: ERROR!!: valid DNSServer bits not zero 0x%x, 0x%x 0x%x 0x%x for question " PRI_DM_NAME " (" PUB_S ")",
+ q->request_id, mDNSVal16(q->TargetQID), q->validDNSServers.l[3], q->validDNSServers.l[2], q->validDNSServers.l[1], q->validDNSServers.l[0], DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype));
// If we reached the end of list while picking DNS servers, then we don't want to deactivate the
// question. Try after 60 seconds. We find this by looking for valid DNSServers for this question,
// if we find any, then we must have tried them before we came here. This avoids maintaining
@@ -4899,7 +4700,9 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
SetValidDNSServers(m, q);
if (mDNSOpaque128IsZero(&q->validDNSServers))
{
- LogInfo("uDNS_CheckCurrentQuestion: no DNS server for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] uDNS_CheckCurrentQuestion: no DNS server for " PRI_DM_NAME " (" PUB_S ")",
+ q->request_id, mDNSVal16(q->TargetQID), DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype));
q->ThisQInterval = 0;
}
else
@@ -4916,28 +4719,30 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
q->qDNSServer = GetServerForQuestion(m, q);
for (qptr = q->next ; qptr; qptr = qptr->next)
if (qptr->DuplicateOf == q) { qptr->validDNSServers = q->validDNSServers; qptr->qDNSServer = q->qDNSServer; }
- {
- mDNSIPPort zp = zeroIPPort;
- LogInfo("uDNS_checkCurrentQuestion: Tried all DNS servers, retry question %p SuppressUnusable %d %##s (%s) with DNS Server %#a:%d after 60 seconds, ThisQInterval %d",
- q, q->SuppressUnusable, q->qname.c, DNSTypeName(q->qtype),
- q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL, mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zp), q->ThisQInterval);
- }
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] uDNS_checkCurrentQuestion: Tried all DNS servers, retry question %p SuppressUnusable %d " PRI_DM_NAME " (" PUB_S ") with DNS Server " PRI_IP_ADDR ":%d after 60 seconds, ThisQInterval %d",
+ q->request_id, mDNSVal16(q->TargetQID), q, q->SuppressUnusable, DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype),
+ q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL, mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort), q->ThisQInterval);
}
}
else
{
q->ThisQInterval = 0;
- LogMsg("uDNS_CheckCurrentQuestion DNS server %#a:%d for %##s is disabled", &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qname.c);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] uDNS_CheckCurrentQuestion DNS server " PRI_IP_ADDR ":%d for " PRI_DM_NAME " is disabled",
+ q->request_id, mDNSVal16(q->TargetQID), &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), DM_NAME_PARAM(&q->qname));
}
if (cg)
{
- for (rr = cg->members; rr; rr=rr->next)
+ for (cr = cg->members; cr; cr=cr->next)
{
- if (SameNameRecordAnswersQuestion(&rr->resrec, q))
+ if (SameNameCacheRecordAnswersQuestion(cr, q))
{
- LogInfo("uDNS_CheckCurrentQuestion: Purged resourcerecord %s", CRDisplayString(m, rr));
- mDNS_PurgeCacheResourceRecord(m, rr);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] uDNS_CheckCurrentQuestion: Purged resourcerecord " PRI_S,
+ q->request_id, mDNSVal16(q->TargetQID), CRDisplayString(m, cr));
+ mDNS_PurgeCacheResourceRecord(m, cr);
}
}
}
@@ -4949,7 +4754,7 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
if (!mDNSOpaque16IsZero(q->responseFlags))
m->rec.r.responseFlags = q->responseFlags;
// We're already using the m->CurrentQuestion pointer, so CacheRecordAdd can't use it to walk the question list.
- // To solve this problem we set rr->DelayDelivery to a nonzero value (which happens to be 'now') so that we
+ // To solve this problem we set cr->DelayDelivery to a nonzero value (which happens to be 'now') so that we
// momentarily defer generating answer callbacks until mDNS_Execute time.
CreateNewCacheEntry(m, slot, cg, NonZeroTime(m->timenow), mDNStrue, mDNSNULL);
ScheduleNextCacheCheckTime(m, slot, NonZeroTime(m->timenow));
@@ -4958,6 +4763,7 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
// MUST NOT touch m->CurrentQuestion (or q) after this -- client callback could have deleted it
}
}
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
}
mDNSexport void CheckNATMappings(mDNS *m)
@@ -5151,7 +4957,9 @@ mDNSlocal mDNSs32 CheckRecordUpdates(mDNS *m)
mDNSexport void uDNS_Tasks(mDNS *const m)
{
mDNSs32 nexte;
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
DNSServer *d;
+#endif
m->NextuDNSEvent = m->timenow + FutureTime;
@@ -5159,21 +4967,28 @@ mDNSexport void uDNS_Tasks(mDNS *const m)
if (m->NextuDNSEvent - nexte > 0)
m->NextuDNSEvent = nexte;
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
for (d = m->DNSServers; d; d=d->next)
if (d->penaltyTime)
{
if (m->timenow - d->penaltyTime >= 0)
{
- LogInfo("DNS server %#a:%d out of penalty box", &d->addr, mDNSVal16(d->port));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "DNS server " PRI_IP_ADDR ":%d out of penalty box", &d->addr, mDNSVal16(d->port));
d->penaltyTime = 0;
}
else
if (m->NextuDNSEvent - d->penaltyTime > 0)
m->NextuDNSEvent = d->penaltyTime;
}
+#endif
if (m->CurrentQuestion)
- LogMsg("uDNS_Tasks ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "uDNS_Tasks ERROR m->CurrentQuestion already set: " PRI_DM_NAME " (" PRI_S ")",
+ DM_NAME_PARAM(&m->CurrentQuestion->qname), DNSTypeName(m->CurrentQuestion->qtype));
+ }
m->CurrentQuestion = m->Questions;
while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
{
@@ -5265,9 +5080,8 @@ mDNSexport void mDNS_AddSearchDomain(const domainname *const domain, mDNSInterfa
else
{
// if domain not in list, add to list, mark as add (1)
- *p = mDNSPlatformMemAllocate(sizeof(SearchListElem));
+ *p = (SearchListElem *) mDNSPlatformMemAllocateClear(sizeof(**p));
if (!*p) { LogMsg("ERROR: mDNS_AddSearchDomain - malloc"); return; }
- mDNSPlatformMemZero(*p, sizeof(SearchListElem));
AssignDomainName(&(*p)->domain, domain);
(*p)->next = mDNSNULL;
(*p)->InterfaceID = InterfaceID;
@@ -5302,7 +5116,7 @@ mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceR
if (AddRecord)
{
- ARListElem *arElem = mDNSPlatformMemAllocate(sizeof(ARListElem));
+ ARListElem *arElem = (ARListElem *) mDNSPlatformMemAllocateClear(sizeof(*arElem));
if (!arElem) { LogMsg("ERROR: FoundDomain out of memory"); return; }
mDNS_SetupResourceRecord(&arElem->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, AuthRecordLocalOnly, FreeARElemCallback, arElem);
MakeDomainNameFromDNSNameString(&arElem->ar.namestorage, name);
@@ -5696,7 +5510,7 @@ mDNSexport void uDNS_StopWABQueries(mDNS *const m, int queryType)
uDNS_SetupWABQueries(m);
}
-mDNSexport domainname *uDNS_GetNextSearchDomain(mDNSInterfaceID InterfaceID, mDNSs8 *searchIndex, mDNSBool ignoreDotLocal)
+mDNSexport domainname *uDNS_GetNextSearchDomain(mDNSInterfaceID InterfaceID, int *searchIndex, mDNSBool ignoreDotLocal)
{
SearchListElem *p = SearchList;
int count = *searchIndex;
@@ -5736,10 +5550,7 @@ mDNSexport domainname *uDNS_GetNextSearchDomain(mDNSInterfaceID InterfaceID, mD
}
// Point to the next one in the list which we will look at next time.
(*searchIndex)++;
- // When we are appending search domains in a ActiveDirectory domain, the question's InterfaceID
- // set to mDNSInterface_Unicast. Match the unscoped entries in that case.
- if (((InterfaceID == mDNSInterface_Unicast) && (p->InterfaceID == mDNSInterface_Any)) ||
- p->InterfaceID == InterfaceID)
+ if (p->InterfaceID == InterfaceID)
{
LogInfo("uDNS_GetNextSearchDomain returning domain %##s, InterfaceID %p", p->domain.c, p->InterfaceID);
return &p->domain;
@@ -5824,240 +5635,666 @@ struct CompileTimeAssertionChecks_uDNS
// other overly-large structures instead of having a pointer to them, can inadvertently
// cause structure sizes (and therefore memory usage) to balloon unreasonably.
char sizecheck_tcpInfo_t [(sizeof(tcpInfo_t) <= 9056) ? 1 : -1];
- char sizecheck_SearchListElem[(sizeof(SearchListElem) <= 6136) ? 1 : -1];
+ char sizecheck_SearchListElem[(sizeof(SearchListElem) <= 6381) ? 1 : -1];
};
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark - DNS Push Notification functions
#endif
-#ifdef DNS_PUSH_ENABLED
-mDNSlocal tcpInfo_t * GetTCPConnectionToPushServer(mDNS *m, DNSQuestion *q)
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
+mDNSlocal void DNSPushProcessResponse(mDNS *const m, const DNSMessage *const msg,
+ DNSPushNotificationServer *server, ResourceRecord *mrr)
{
- DNSPushNotificationZone *zone;
- DNSPushNotificationServer *server;
- DNSPushNotificationZone *newZone;
- DNSPushNotificationServer *newServer;
+ // "(CacheRecord*)1" is a special (non-zero) end-of-list marker
+ // We use this non-zero marker so that records in our CacheFlushRecords list will always have NextInCFList
+ // set non-zero, and that tells GetCacheEntity() that they're not, at this moment, eligible for recycling.
+ CacheRecord *CacheFlushRecords = (CacheRecord*)1;
+ CacheRecord **cfp = &CacheFlushRecords;
+ enum { removeName, removeClass, removeRRset, removeRR, addRR } action;
- // If we already have a question for this zone and if the server is the same, reuse it
- for (zone = m->DNSPushZones; zone != mDNSNULL; zone = zone->next)
+ // Ignore records we don't want to cache.
+
+ // Don't want to cache OPT or TSIG pseudo-RRs
+ if (mrr->rrtype == kDNSType_TSIG)
{
- if (SameDomainName(&q->nta->ChildName, &zone->zoneName))
+ return;
+ }
+ if (mrr->rrtype == kDNSType_OPT)
+ {
+ return;
+ }
+
+ if ((mrr->rrtype == kDNSType_CNAME) && SameDomainName(mrr->name, &mrr->rdata->u.name))
+ {
+ LogInfo("DNSPushProcessResponse: CNAME loop domain name %##s", mrr->name->c);
+ return;
+ }
+
+ // TTL == -1: delete individual record
+ // TTL == -2: wildcard delete
+ // CLASS != ANY, TYPE != ANY: delete all records of specified type and class
+ // CLASS != ANY, TYPE == ANY: delete all RRs of specified class
+ // CLASS == ANY: delete all RRs on the name, regardless of type or class (TYPE is ignored).
+ // If TTL is zero, this is a delete, not an add.
+ if ((mDNSs32)mrr->rroriginalttl == -1)
+ {
+ LogMsg("DNSPushProcessResponse: Got remove on %##s with type %s",
+ mrr->name, DNSTypeName(mrr->rrtype));
+ action = removeRR;
+ }
+ else if ((mDNSs32)mrr->rroriginalttl == -2)
+ {
+ if (mrr->rrclass == kDNSQClass_ANY)
{
- DNSPushNotificationServer *zoneServer = mDNSNULL;
- for (zoneServer = zone->servers; zoneServer != mDNSNULL; zoneServer = zoneServer->next)
+ LogMsg("DNSPushProcessResponse: Got Remove Name on %##s", mrr->name);
+ action = removeName;
+ }
+ else if (mrr->rrtype == kDNSQType_ANY)
+ {
+ LogMsg("DNSPushProcessResponse: Got Remove Name on %##s", mrr->name);
+ action = removeClass;
+ }
+ else
+ {
+ LogMsg("DNSPushProcessResponse: Got Remove RRset on %##s, type %s, rdlength %d",
+ mrr->name, DNSTypeName(mrr->rrtype), mrr->rdlength);
+ action = removeRRset;
+ }
+ }
+ else
+ {
+ action = addRR;
+ }
+
+ if (action != addRR)
+ {
+ if (m->rrcache_size)
+ {
+ CacheRecord *rr;
+ // Remember the unicast question that we found, which we use to make caching
+ // decisions later on in this function
+ CacheGroup *cg = CacheGroupForName(m, mrr->namehash, mrr->name);
+ for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
{
- if (mDNSSameAddress(&q->dnsPushServerAddr, &zoneServer->serverAddr))
+ if ( action == removeName ||
+ (action == removeClass && rr->resrec.rrclass == mrr->rrclass) ||
+ (rr->resrec.rrclass == mrr->rrclass &&
+ ((action == removeRRset && rr->resrec.rrtype == mrr->rrtype) ||
+ (action == removeRR && rr->resrec.rrtype == mrr->rrtype &&
+ SameRDataBody(mrr, &rr->resrec.rdata->u, SameDomainName)))))
{
- zone->numberOfQuestions++;
- zoneServer->numberOfQuestions++;
- return zoneServer->connection;
+ LogInfo("DNSPushProcessResponse purging %##s (%s) %s",
+ rr->resrec.name, DNSTypeName(mrr->rrtype), CRDisplayString(m, rr));
+ // We've found a cache entry to delete. Now what?
+ mDNS_PurgeCacheResourceRecord(m, rr);
}
}
}
}
-
- // If we have a connection to this server but it is for a differnt zone, create a new zone entry and reuse the connection
- for (server = m->DNSPushServers; server != mDNSNULL; server = server->next)
+ else
{
- if (mDNSSameAddress(&q->dnsPushServerAddr, &server->serverAddr))
+ // It's an add.
+ LogMsg("DNSPushProcessResponse: Got add RR on %##s, type %s, length %d",
+ mrr->name, DNSTypeName(mrr->rrtype), mrr->rdlength);
+
+ // When we receive DNS Push responses, we assume a long cache lifetime --
+ // This path is only reached for DNS Push responses; as long as the connection to the server is
+ // live, the RR should stay updated.
+ mrr->rroriginalttl = kLLQ_DefLease /* XXX */;
+
+ // Use the DNS Server we remember from the question that created this DNS Push server structure.
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ mdns_replace(&mrr->dnsservice, server->dnsservice);
+#else
+ mrr->rDNSServer = server->qDNSServer;
+#endif
+
+ // 2. See if we want to add this packet resource record to our cache
+ // We only try to cache answers if we have a cache to put them in
+ if (m->rrcache_size)
{
- newZone = mDNSPlatformMemAllocate(sizeof(DNSPushNotificationZone));
- newZone->numberOfQuestions = 1;
- newZone->zoneName = q->nta->ChildName;
- newZone->servers = server;
+ const mDNSu32 slot = HashSlotFromNameHash(mrr->namehash);
+ CacheGroup *cg = CacheGroupForName(m, mrr->namehash, mrr->name);
+ CacheRecord *rr = mDNSNULL;
- // Add the new zone to the begining of the list
- newZone->next = m->DNSPushZones;
- m->DNSPushZones = newZone;
+ // 2a. Check if this packet resource record is already in our cache.
+ rr = mDNSCoreReceiveCacheCheck(m, msg, uDNS_LLQ_Events, slot, cg, &cfp, mDNSNULL);
- server->numberOfQuestions++;
- return server->connection;
+ // If packet resource record not in our cache, add it now
+ // (unless it is just a deletion of a record we never had, in which case we don't care)
+ if (!rr && mrr->rroriginalttl > 0)
+ {
+ rr = CreateNewCacheEntry(m, slot, cg, 0,
+ mDNStrue, &server->connection->transport->remote_addr);
+ if (rr)
+ {
+ // Not clear that this is ever used, but for verisimilitude, set this to look like
+ // an authoritative response to a regular query.
+ rr->responseFlags.b[0] = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery | kDNSFlag0_AA;
+ rr->responseFlags.b[1] = kDNSFlag1_RC_NoErr | kDNSFlag0_AA;
+ }
+ }
}
}
+}
- // If we do not have any existing connections, create a new connection
- newServer = mDNSPlatformMemAllocate(sizeof(DNSPushNotificationServer));
- newZone = mDNSPlatformMemAllocate(sizeof(DNSPushNotificationZone));
-
- newServer->numberOfQuestions = 1;
- newServer->serverAddr = q->dnsPushServerAddr;
- newServer->connection = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &q->dnsPushServerAddr, q->dnsPushServerPort, &q->nta->Host, q, mDNSNULL);
-
- newZone->numberOfQuestions = 1;
- newZone->zoneName = q->nta->ChildName;
- newZone->servers = newServer;
-
- // Add the new zone to the begining of the list
- newZone->next = m->DNSPushZones;
- m->DNSPushZones = newZone;
-
- newServer->next = m->DNSPushServers;
- m->DNSPushServers = newServer;
- return newServer->connection;
+mDNSlocal void DNSPushProcessResponses(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *firstAnswer,
+ const mDNSu8 *const end, DNSPushNotificationServer *server)
+{
+ DNSQuestion *q;
+ const mDNSu8 *ptr = firstAnswer;
+ mDNSIPPort port;
+ port.NotAnInteger = 0;
+ ResourceRecord *mrr = &m->rec.r.resrec;
+
+ // Validate the contents of the message
+ // XXX Right now this code will happily parse all the valid data and then hit invalid data
+ // and give up. I don't think there's a risk here, but we should discuss it.
+ // XXX what about source validation? Like, if we have a VPN, are we safe? I think yes, but let's think about it.
+ while ((ptr = GetLargeResourceRecord(m, msg, ptr, end, mDNSNULL, kDNSRecordTypePacketAns, &m->rec)))
+ {
+ int gotOne = 0;
+ for (q = m->Questions; q; q = q->next)
+ {
+ if (q->LongLived &&
+ (q->qtype == mrr->rrtype || q->qtype == kDNSServiceType_ANY)
+ && q->qnamehash == mrr->namehash && SameDomainName(&q->qname, mrr->name))
+ {
+ LogMsg("DNSPushProcessResponses found %##s (%s) %d %s %s",
+ q->qname.c, DNSTypeName(q->qtype), q->state,
+ q->dnsPushServer ? (q->dnsPushServer->connection
+ ? q->dnsPushServer->connection->remote_name
+ : "<no push server>") : "<no push server>",
+ server->connection->remote_name);
+ if (q->dnsPushServer == server)
+ {
+ gotOne++;
+ DNSPushProcessResponse(m, msg, server, mrr);
+ break; // question list may have changed
+ }
+ }
+ }
+ if (!gotOne) {
+ LogMsg("DNSPushProcessResponses: no match for %##s %d %d", mrr->name, mrr->rrtype, mrr->rrclass);
+ }
+ mrr->RecordType = 0; // Clear RecordType to show we're not still using it
+ }
+}
+
+static void
+DNSPushStartConnecting(DNSPushNotificationServer *server)
+{
+ if (dso_connect(server->connectInfo))
+ {
+ server->connectState = DNSPushServerConnectionInProgress;
+ }
+ else
+ {
+ server->connectState = DNSPushServerConnectFailed;
+ }
}
-mDNSexport void DiscoverDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
+mDNSexport void DNSPushReconcileConnection(mDNS *m, DNSQuestion *q)
{
- /* Use the same NAT setup as in the LLQ case */
- if (m->LLQNAT.clientContext != mDNSNULL) // LLQNAT just started, give it some time
+ DNSPushNotificationZone *zone;
+ DNSPushNotificationZone *nextZone;
+
+ if (q->dnsPushServer == mDNSNULL)
{
- LogInfo("startLLQHandshake: waiting for NAT status for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- q->ThisQInterval = LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10); // Retry in approx 15 minutes
- q->LastQTime = m->timenow;
- SetNextQueryTime(m, q);
return;
}
+
+ // Update the counts
+ for (zone = m->DNSPushZones; zone != mDNSNULL; zone = zone->next)
+ {
+ if (zone->server == q->dnsPushServer)
+ {
+ zone->numberOfQuestions--;
+ }
+ }
+ q->dnsPushServer->numberOfQuestions--;
- // Either we don't have {PCP, NAT-PMP, UPnP/IGD} support (ExternalPort is zero) or behind a Double NAT that may or
- // may not have {PCP, NAT-PMP, UPnP/IGD} support (NATResult is non-zero)
- if (mDNSIPPortIsZero(m->LLQNAT.ExternalPort) || m->LLQNAT.Result)
+ nextZone = mDNSNULL;
+ for (zone = m->DNSPushZones; zone != mDNSNULL; zone = nextZone)
{
- LogInfo("startLLQHandshake: Cannot receive inbound packets; will poll for %##s (%s) External Port %d, NAT Result %d",
- q->qname.c, DNSTypeName(q->qtype), mDNSVal16(m->LLQNAT.ExternalPort), m->LLQNAT.Result);
- StartLLQPolling(m, q); // Actually sets up the NAT Auto Tunnel
+ nextZone = zone->next;
+ if (zone->numberOfQuestions == 0)
+ {
+ if (zone == m->DNSPushZones)
+ m->DNSPushZones = nextZone;
+ LogInfo("DNSPushReconcileConnection: zone %##s is being freed", &zone->zoneName);
+ mDNSPlatformMemFree(zone);
+ }
+ }
+
+ q->dnsPushServer = mDNSNULL;
+}
+
+static const char kDNSPushActivity_Subscription[] = "dns-push-subscription";
+
+static void DNSPushSendKeepalive(DNSPushNotificationServer *server, mDNSu32 inactivity_timeout, mDNSu32 keepalive_interval)
+{
+ dso_message_t state;
+ dso_transport_t *transport = server->connection->transport;
+ if (transport == NULL || transport->outbuf == NULL) {
+ // Should be impossible, don't crash.
+ LogInfo("DNSPushNotificationSendSubscribe: no transport!");
return;
}
+ dso_make_message(&state, transport->outbuf, transport->outbuf_size, server->connection, false, 0);
+ dso_start_tlv(&state, kDSOType_Keepalive);
+ dso_add_tlv_u32(&state, inactivity_timeout);
+ dso_add_tlv_u32(&state, keepalive_interval);
+ dso_finish_tlv(&state);
+ dso_message_write(server->connection, &state, mDNSfalse);
+}
- if (mDNSIPPortIsZero(q->dnsPushServerPort) && q->dnsPushState == DNSPUSH_INIT)
- {
- LogInfo("SubscribeToDNSPushNotificationServer: StartGetZoneData for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- q->ThisQInterval = LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10); // Retry in approx 15 minutes
- q->LastQTime = m->timenow;
- SetNextQueryTime(m, q);
- q->dnsPushServerAddr = zeroAddr;
- // We know q->dnsPushServerPort is zero because of check above
- if (q->nta) CancelGetZoneData(m, q->nta);
- q->nta = StartGetZoneData(m, &q->qname, ZoneServiceDNSPush, DNSPushNotificationGotZoneData, q);
+static void DNSPushNotificationSendSubscriptionChange(mDNSBool subscribe, dso_state_t *dso, DNSQuestion *q)
+{
+ dso_message_t state;
+ dso_transport_t *transport = dso->transport;
+ mDNSu16 len;
+ if (transport == NULL || transport->outbuf == NULL) {
+ // Should be impossible, don't crash.
+ LogInfo("DNSPushNotificationSendSubscribe: no transport!");
return;
}
+ dso_make_message(&state, transport->outbuf, transport->outbuf_size, dso, subscribe ? false : true, q);
+ dso_start_tlv(&state, subscribe ? kDSOType_DNSPushSubscribe : kDSOType_DNSPushUnsubscribe);
+ len = DomainNameLengthLimit(&q->qname, q->qname.c + (sizeof q->qname));
+ dso_add_tlv_bytes(&state, q->qname.c, len);
+ dso_add_tlv_u16(&state, q->qtype);
+ dso_add_tlv_u16(&state, q->qclass);
+ dso_finish_tlv(&state);
+ dso_message_write(dso, &state, mDNSfalse);
+}
- if (q->tcp)
+static void DNSPushStop(mDNS *m, DNSPushNotificationServer *server)
+{
+ mDNSBool found = mDNStrue;
+ DNSQuestion *q;
+ while (found)
{
- LogInfo("SubscribeToDNSPushNotificationServer: Disposing existing TCP connection for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- DisposeTCPConn(q->tcp);
- q->tcp = mDNSNULL;
+ found = mDNSfalse;
+ server->connectState = DNSPushServerNoDNSPush;
+
+ for (q = m->Questions; q; q = q->next)
+ {
+ if (q->dnsPushServer == server)
+ {
+ DNSPushReconcileConnection(m, q);
+ q->dnsPushServer = NULL;
+ q->state = LLQ_Poll;
+ q->ThisQInterval = 0;
+ q->LastQTime = m->timenow;
+ SetNextQueryTime(m, q);
+ break;
+ }
+ }
}
+}
- if (!q->nta)
+mDNSexport void DNSPushServerDrop(DNSPushNotificationServer *server)
+{
+ if (server->connection)
{
- // Normally we lookup the zone data and then call this function. And we never free the zone data
- // for "PrivateQuery". But sometimes this can happen due to some race conditions. When we
- // switch networks, we might end up "Polling" the network e.g., we are behind a Double NAT.
- // When we poll, we free the zone information as we send the query to the server (See
- // PrivateQueryGotZoneData). The NAT callback (LLQNATCallback) may happen soon after that. If we
- // are still behind Double NAT, we would have returned early in this function. But we could
- // have switched to a network with no NATs and we should get the zone data again.
- LogInfo("SubscribeToDNSPushNotificationServer: nta is NULL for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- q->nta = StartGetZoneData(m, &q->qname, ZoneServiceDNSPush, DNSPushNotificationGotZoneData, q);
- return;
+ dso_drop(server->connection);
+ server->connection = NULL;
}
- else if (!q->nta->Host.c[0])
+ if (server->connectInfo)
{
- // This should not happen. If it happens, we print a log and MakeTCPConn will fail if it can't find a hostname
- LogMsg("SubscribeToDNSPushNotificationServer: ERROR!!: nta non NULL for %##s (%s) but HostName %d NULL, LongLived %d", q->qname.c, DNSTypeName(q->qtype), q->nta->Host.c[0], q->LongLived);
+ dso_connect_state_drop(server->connectInfo);
}
- q->tcp = GetTCPConnectionToPushServer(m,q);
- // If TCP failed (transient networking glitch) try again in five seconds
- q->ThisQInterval = (q->tcp != mDNSNULL) ? q->ThisQInterval = 0 : (mDNSPlatformOneSecond * 5);
- q->LastQTime = m->timenow;
- SetNextQueryTime(m, q);
}
-
-mDNSexport void SubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
+static void DNSPushServerFree(mDNS *m, DNSPushNotificationServer *server)
{
- mDNSu8 *end = mDNSNULL;
- InitializeDNSMessage(&m->omsg.h, zeroID, SubscribeFlags);
- end = putQuestion(&m->omsg, end, m->omsg.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
- if (!end)
+ DNSPushNotificationServer **sp;
+ DNSPushServerDrop(server);
+
+ sp = &m->DNSPushServers;
+ while (*sp)
{
- LogMsg("ERROR: SubscribeToDNSPushNotificationServer putQuestion failed");
- return;
+ if (*sp == server)
+ {
+ *sp = server->next;
+ break;
+ }
+ else
+ {
+ sp = &server->next;
+ }
}
+ mDNSPlatformMemFree(server);
+}
- mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, q->LocalSocket, &q->dnsPushServerAddr, q->dnsPushServerPort, q->tcp->sock, mDNSNULL, mDNSfalse);
+static void DNSPushDSOCallback(void *context, const void *event_context,
+ dso_state_t *dso, dso_event_type_t eventType)
+{
+ const DNSMessage *message;
+ DNSPushNotificationServer *server = context;
+ dso_activity_t *activity;
+ const dso_query_receive_context_t *receive_context;
+ const dso_disconnect_context_t *disconnect_context;
+ const dso_keepalive_context_t *keepalive_context;
+ DNSQuestion *q;
+ uint16_t rcode;
+ mDNSs32 reconnect_when = 0;
+ mDNS *m = server->m;
- // update question state
- q->dnsPushState = DNSPUSH_ESTABLISHED;
- q->ThisQInterval = (kLLQ_INIT_RESEND * mDNSPlatformOneSecond);
- q->LastQTime = m->timenow;
- SetNextQueryTime(m, q);
+ mDNS_CheckLock(m);
+
+ switch(eventType)
+ {
+ case kDSOEventType_DNSMessage:
+ // We shouldn't get here because we won't use this connection for DNS messages.
+ message = event_context;
+ LogMsg("DNSPushDSOCallback: DNS Message (opcode=%d) received from %##s",
+ (message->h.flags.b[0] & kDNSFlag0_OP_Mask) >> 3, &server->serverName);
+ break;
+
+ case kDSOEventType_DNSResponse:
+ // We shouldn't get here because we already handled any DNS messages
+ message = event_context;
+ LogMsg("DNSPushDSOCallback: DNS Response (opcode=%d) received from %##s",
+ (message->h.flags.b[0] & kDNSFlag0_OP_Mask) >> 3, &server->serverName);
+ break;
+
+ case kDSOEventType_DSOMessage:
+ message = event_context;
+ if (dso->primary.opcode == kDSOType_DNSPushUpdate) {
+ DNSPushProcessResponses(server->m, message, dso->primary.payload,
+ dso->primary.payload + dso->primary.length, server);
+ } else {
+ dso_send_not_implemented(dso, &message->h);
+ LogMsg("DNSPushDSOCallback: Unknown DSO Message (Primary TLV=%d) received from %##s",
+ dso->primary.opcode, &server->serverName);
+ }
+ break;
+
+ case kDSOEventType_DSOResponse:
+ receive_context = event_context;
+ q = receive_context->query_context;
+ rcode = receive_context->rcode;
+ if (q) {
+ // If we got an error on a subscribe, we need to evaluate what went wrong
+ if (rcode == kDNSFlag1_RC_NoErr) {
+ LogMsg("DNSPushDSOCallback: Subscription for %##s/%d/%d succeeded.", q->qname.c, q->qtype, q->qclass);
+ q->state = LLQ_DNSPush_Established;
+ server->connectState = DNSPushServerSessionEstablished;
+ } else {
+ // Don't use this server.
+ q->dnsPushServer->connectState = DNSPushServerNoDNSPush;
+ q->state = LLQ_Poll;
+ q->ThisQInterval = 0;
+ q->LastQTime = m->timenow;
+ SetNextQueryTime(m, q);
+ LogMsg("DNSPushDSOCallback: Subscription for %##s/%d/%d failed.", q->qname.c, q->qtype, q->qclass);
+ }
+ } else {
+ LogMsg("DNSPushDSOCallback: DSO Response (Primary TLV=%d) (RCODE=%d) (no query) received from %##s",
+ dso->primary.opcode, receive_context->rcode, &server->serverName);
+ server->connectState = DNSPushServerSessionEstablished;
+ }
+ break;
+
+ case kDSOEventType_Finalize:
+ LogMsg("DNSPushDSOCallback: Finalize");
+ break;
+
+ case kDSOEventType_Connected:
+ LogMsg("DNSPushDSOCallback: Connected to %##s", &server->serverName);
+ server->connectState = DNSPushServerConnected;
+ for (activity = dso->activities; activity; activity = activity->next) {
+ DNSPushNotificationSendSubscriptionChange(mDNStrue, dso, activity->context);
+ }
+ break;
+
+ case kDSOEventType_ConnectFailed:
+ DNSPushStop(m, server);
+ LogMsg("DNSPushDSOCallback: Connection to %##s failed", &server->serverName);
+ break;
+
+ case kDSOEventType_Disconnected:
+ disconnect_context = event_context;
+
+ // If a network glitch broke the connection, try to reconnect immediately. But if this happens
+ // twice, don't just blindly reconnect.
+ if (disconnect_context->reconnect_delay == 0) {
+ if ((server->lastDisconnect + 90 * mDNSPlatformOneSecond) - m->timenow > 0) {
+ reconnect_when = 3600000; // If we get two disconnects in quick succession, wait an hour before trying again.
+ } else {
+ DNSPushStartConnecting(server);
+ LogMsg("DNSPushDSOCallback: Connection to %##s disconnected, trying immediate reconnect",
+ &server->serverName);
+ }
+ } else {
+ reconnect_when = disconnect_context->reconnect_delay;
+ }
+ if (reconnect_when != 0) {
+ LogMsg("DNSPushDSOCallback: Holding server %##s out as not reconnectable for %lf seconds",
+ &server->serverName, 1000.0 * (reconnect_when - m->timenow) / (double)mDNSPlatformOneSecond);
+ dso_schedule_reconnect(m, server->connectInfo, reconnect_when);
+ }
+ server->lastDisconnect = m->timenow;
+ server->connection = mDNSNULL;
+ break;
+
+ // We don't reconnect unless there is demand. The reason we have this event is so that we can
+ // leave the DNSPushNotificationServer data structure around to _prevent_ attempts to reconnect
+ // before the reconnect delay interval has expired. When we get this call, we just free up the
+ // server.
+ case kDSOEventType_ShouldReconnect:
+ // This should be unnecessary, but it would be bad to accidentally have a question pointing at
+ // a server that had been freed, so make sure we don't.
+ LogMsg("DNSPushDSOCallback: ShouldReconnect timer for %##s fired, disposing of it.", &server->serverName);
+ DNSPushStop(m, server);
+ DNSPushServerFree(m, server);
+ break;
+
+ case kDSOEventType_Keepalive:
+ LogMsg("DNSPushDSOCallback: Keepalive timer for %##s fired.", &server->serverName);
+ keepalive_context = event_context;
+ DNSPushSendKeepalive(server, keepalive_context->inactivity_timeout, keepalive_context->keepalive_interval);
+ break;
+
+ case kDSOEventType_KeepaliveRcvd:
+ LogMsg("DNSPushDSOCallback: Keepalive message received from %##s.", &server->serverName);
+ break;
+
+ case kDSOEventType_Inactive:
+ // The set of activities went to zero, and we set the idle timeout. And it expired without any
+ // new activities starting. So we can disconnect.
+ LogMsg("DNSPushDSOCallback: Inactivity timer for %##s fired, disposing of it.", &server->serverName);
+ DNSPushStop(m, server);
+ DNSPushServerFree(m, server);
+ break;
+ case kDSOEventType_RetryDelay:
+ disconnect_context = event_context;
+ DNSPushStop(m, server);
+ dso_schedule_reconnect(m, server->connectInfo, disconnect_context->reconnect_delay);
+ break;
+ }
}
-mDNSlocal void reconcileDNSPushConnection(mDNS *m, DNSQuestion *q)
+DNSPushNotificationServer *GetConnectionToDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
{
DNSPushNotificationZone *zone;
DNSPushNotificationServer *server;
- DNSPushNotificationServer *nextServer;
- DNSPushNotificationZone *nextZone;
+ DNSPushNotificationZone *newZone;
+ DNSPushNotificationServer *newServer;
+ char name[MAX_ESCAPED_DOMAIN_NAME];
- // Update the counts
+ // If we already have a question for this zone and if the server is the same, reuse it
for (zone = m->DNSPushZones; zone != mDNSNULL; zone = zone->next)
{
- if (SameDomainName(&zone->zoneName, &q->nta->ChildName))
+ LogMsg("GetConnectionToDNSPushNotificationServer: zone compare zone %##s question %##s", &zone->zoneName, &q->nta->ChildName);
+ if (SameDomainName(&q->nta->ChildName, &zone->zoneName))
{
- zone->numberOfQuestions--;
- for (server = zone->servers; server != mDNSNULL; server = server->next)
- {
- if (mDNSSameAddress(&server->serverAddr, &q->dnsPushServerAddr))
- server->numberOfQuestions--;
+ DNSPushNotificationServer *zoneServer = mDNSNULL;
+ zoneServer = zone->server;
+ if (zoneServer != mDNSNULL) {
+ LogMsg("GetConnectionToDNSPushNotificationServer: server compare server %##s question %##s",
+ &zoneServer->serverName, &q->nta->Host);
+ if (SameDomainName(&q->nta->Host, &zoneServer->serverName))
+ {
+ LogMsg("GetConnectionToDNSPushNotificationServer: server and zone already present.");
+ zone->numberOfQuestions++;
+ zoneServer->numberOfQuestions++;
+ return zoneServer;
+ }
}
}
}
- // Now prune the lists
- server = m->DNSPushServers;
- nextServer = mDNSNULL;
- while(server != mDNSNULL)
+ // If we have a connection to this server but it is for a differnt zone, create a new zone entry and reuse the connection
+ for (server = m->DNSPushServers; server != mDNSNULL; server = server->next)
{
- nextServer = server->next;
- if (server->numberOfQuestions <= 0)
+ LogMsg("GetConnectionToDNSPushNotificationServer: server compare server %##s question %##s",
+ &server->serverName, &q->nta->Host);
+ if (SameDomainName(&q->nta->Host, &server->serverName))
{
- DisposeTCPConn(server->connection);
- if (server == m->DNSPushServers)
- m->DNSPushServers = nextServer;
- mDNSPlatformMemFree(server);
- server = nextServer;
+ newZone = (DNSPushNotificationZone *) mDNSPlatformMemAllocateClear(sizeof(*newZone));
+ if (newZone == NULL)
+ {
+ return NULL;
+ }
+ newZone->numberOfQuestions = 1;
+ newZone->zoneName = q->nta->ChildName;
+ newZone->server = server;
+
+ // Add the new zone to the begining of the list
+ newZone->next = m->DNSPushZones;
+ m->DNSPushZones = newZone;
+
+ server->numberOfQuestions++;
+ LogMsg("GetConnectionToDNSPushNotificationServer: server already present.");
+ return server;
}
- else server = server->next;
}
- zone = m->DNSPushZones;
- nextZone = mDNSNULL;
- while(zone != mDNSNULL)
+ // If we do not have any existing connections, create a new connection
+ newServer = (DNSPushNotificationServer *) mDNSPlatformMemAllocateClear(sizeof(*newServer));
+ if (newServer == NULL)
{
- nextZone = zone->next;
- if (zone->numberOfQuestions <= 0)
- {
- if (zone == m->DNSPushZones)
- m->DNSPushZones = nextZone;
- mDNSPlatformMemFree(zone);
- zone = nextZone;
- }
- else zone = zone->next;
+ return NULL;
+ }
+ newZone = (DNSPushNotificationZone *) mDNSPlatformMemAllocateClear(sizeof(*newZone));
+ if (newZone == NULL)
+ {
+ mDNSPlatformMemFree(newServer);
+ return NULL;
}
+ newServer->m = m;
+ newServer->numberOfQuestions = 1;
+ AssignDomainName(&newServer->serverName, &q->nta->Host);
+ newServer->port = q->nta->Port;
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ mdns_replace(&newServer->dnsservice, q->dnsservice);
+#else
+ newServer->qDNSServer = q->qDNSServer;
+#endif
+ ConvertDomainNameToCString(&newServer->serverName, name);
+ newServer->connection = dso_create(mDNSfalse, 10, name, DNSPushDSOCallback, newServer, NULL);
+ if (newServer->connection == NULL)
+ {
+ mDNSPlatformMemFree(newServer);
+ mDNSPlatformMemFree(newZone);
+ return NULL;
+ }
+ newServer->connectInfo = dso_connect_state_create(name, mDNSNULL, newServer->port, 10,
+ AbsoluteMaxDNSMessageData, AbsoluteMaxDNSMessageData,
+ DNSPushDSOCallback, newServer->connection, newServer, "GetDSOConnectionToPushServer");
+ if (newServer->connectInfo)
+ {
+ dso_connect_state_use_tls(newServer->connectInfo);
+ DNSPushStartConnecting(newServer);
+ }
+ else
+ {
+ newServer->connectState = DNSPushServerConnectFailed;
+ }
+ newZone->numberOfQuestions = 1;
+ newZone->zoneName = q->nta->ChildName;
+ newZone->server = newServer;
+
+ // Add the new zone to the begining of the list
+ newZone->next = m->DNSPushZones;
+ m->DNSPushZones = newZone;
+
+ newServer->next = m->DNSPushServers;
+ m->DNSPushServers = newServer;
+ LogMsg("GetConnectionToDNSPushNotificationServer: allocated new server.");
+
+ return newServer;
}
-mDNSexport void UnSubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
+DNSPushNotificationServer *SubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
{
- mDNSu8 *end = mDNSNULL;
- InitializeDNSMessage(&m->omsg.h, q->TargetQID, UnSubscribeFlags);
- end = putQuestion(&m->omsg, end, m->omsg.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
- if (!end)
+ DNSPushNotificationServer *server = GetConnectionToDNSPushNotificationServer(m, q);
+ char name[MAX_ESCAPED_DOMAIN_NAME + 9]; // type(hex)+class(hex)+name
+ dso_activity_t *activity;
+ if (server == mDNSNULL) return server;
+
+ // Now we have a connection to a push notification server. It may be pending, or it may be active,
+ // but either way we can add a DNS Push subscription to the server object.
+ mDNS_snprintf(name, sizeof name, "%04x%04x", q->qtype, q->qclass);
+ ConvertDomainNameToCString(&q->qname, &name[8]);
+ activity = dso_add_activity(server->connection, name, kDNSPushActivity_Subscription, q, mDNSNULL);
+ if (activity == mDNSNULL)
{
- LogMsg("ERROR: UnSubscribeToDNSPushNotificationServer - putQuestion failed");
- return;
+ LogInfo("SubscribeToDNSPushNotificationServer: failed to add question %##s", &q->qname);
+ return mDNSNULL;
}
+ // If we're already connected, send the subscribe request immediately.
+ if (server->connectState == DNSPushServerConnected || server->connectState == DNSPushServerSessionEstablished)
+ {
+ DNSPushNotificationSendSubscriptionChange(mDNStrue, server->connection, q);
+ }
+ return server;
+}
- mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, q->LocalSocket, &q->dnsPushServerAddr, q->dnsPushServerPort, q->tcp->sock, mDNSNULL, mDNSfalse);
+mDNSexport void DiscoverDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
+{
+ LogInfo("DiscoverDNSPushNotificationServer: StartGetZoneData for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ q->ThisQInterval = LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10); // Retry in approx 15 minutes
+ q->LastQTime = m->timenow;
+ SetNextQueryTime(m, q);
+ if (q->nta) CancelGetZoneData(m, q->nta);
+ q->nta = StartGetZoneData(m, &q->qname, ZoneServiceDNSPush, DNSPushNotificationGotZoneData, q);
+ q->state = LLQ_DNSPush_ServerDiscovery;
+}
- reconcileDNSPushConnection(m, q);
+mDNSexport void UnSubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
+{
+ dso_activity_t *activity;
+
+ if (q->dnsPushServer != mDNSNULL)
+ {
+ if (q->dnsPushServer->connection != mDNSNULL)
+ {
+ if (q->dnsPushServer->connectState == DNSPushServerSessionEstablished ||
+ q->dnsPushServer->connectState == DNSPushServerConnected)
+ {
+ // Ignore any response we get to a pending subscribe.
+ dso_ignore_response(q->dnsPushServer->connection, q);
+ DNSPushNotificationSendSubscriptionChange(mDNSfalse, q->dnsPushServer->connection, q);
+ }
+ // activities linger even if we are not connected.
+ activity = dso_find_activity(q->dnsPushServer->connection, mDNSNULL, kDNSPushActivity_Subscription, q);
+ if (activity != mDNSNULL) {
+ dso_drop_activity(q->dnsPushServer->connection, activity);
+ }
+ }
+ DNSPushReconcileConnection(m, q);
+ }
+ // We let the DSO Idle mechanism clean up the connection to the server.
}
+#endif // MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
-#endif // DNS_PUSH_ENABLED
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
#endif
@@ -6169,7 +6406,7 @@ mDNSexport void RetrySearchDomainQuestions(mDNS *const m)
(void) m;
}
-mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info, const domainname *domain, const domainname *keyname, const char *b64keydata, const domainname *hostname, mDNSIPPort *port, mDNSBool autoTunnel)
+mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info, const domainname *domain, const domainname *keyname, const char *b64keydata, const domainname *hostname, mDNSIPPort *port)
{
(void) m;
(void) info;
@@ -6178,7 +6415,6 @@ mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info, const
(void) b64keydata;
(void) hostname;
(void) port;
- (void) autoTunnel;
return mStatus_UnsupportedErr;
}
@@ -6217,8 +6453,8 @@ mDNSexport mStatus mDNS_StopNATOperation(mDNS *const m, NATTraversalInfo *traver
}
mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSs32 serviceID, const mDNSAddr *addr,
- const mDNSIPPort port, mDNSu32 scoped, mDNSu32 timeout, mDNSBool cellIntf, mDNSBool isExpensive, mDNSu16 resGroupID,
- mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO)
+ const mDNSIPPort port, ScopeType scopeType, mDNSu32 timeout, mDNSBool isCell, mDNSBool isExpensive, mDNSBool isConstrained, mDNSBool isCLAT46,
+ mDNSu32 resGroupID, mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO)
{
(void) m;
(void) d;
@@ -6226,10 +6462,12 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons
(void) serviceID;
(void) addr;
(void) port;
- (void) scoped;
+ (void) scopeType;
(void) timeout;
- (void) cellIntf;
+ (void) isCell;
(void) isExpensive;
+ (void) isCLAT46;
+ (void) isConstrained;
(void) resGroupID;
(void) reqA;
(void) reqAAAA;
@@ -6308,3 +6546,13 @@ mDNSexport void DiscoverDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
}
#endif // !UNICAST_DISABLED
+
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
diff --git a/usr/src/contrib/mDNSResponder/mDNSCore/uDNS.h b/usr/src/contrib/mDNSResponder/mDNSCore/uDNS.h
index 0a0622784d..bb5f0c07c9 100755
--- a/usr/src/contrib/mDNSResponder/mDNSCore/uDNS.h
+++ b/usr/src/contrib/mDNSResponder/mDNSCore/uDNS.h
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2013 Apple Computer, Inc. All rights reserved.
+/*
+ * Copyright (c) 2002-2020 Apple Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,6 +19,13 @@
#include "mDNSEmbeddedAPI.h"
#include "DNSCommon.h"
+#include <sys/types.h>
+#include "dns_sd.h"
+
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
+#include "dso.h"
+#include "dso-transport.h"
+#endif
#ifdef __cplusplus
extern "C" {
@@ -32,7 +38,6 @@ extern "C" {
//#define MAX_UCAST_POLL_INTERVAL (1 * 60 * mDNSPlatformOneSecond)
#define LLQ_POLL_INTERVAL (15 * 60 * mDNSPlatformOneSecond) // Polling interval for zones w/ an advertised LLQ port (ie not static zones) if LLQ fails due to NAT, etc.
#define RESPONSE_WINDOW (60 * mDNSPlatformOneSecond) // require server responses within one minute of request
-#define MAX_DNSSEC_UNANSWERED_QUERIES 1 // number of unanswered queries from any one uDNS server before turning off DNSSEC Validation
#define MAX_UCAST_UNANSWERED_QUERIES 2 // number of unanswered queries from any one uDNS server before trying another server
#define DNSSERVER_PENALTY_TIME (60 * mDNSPlatformOneSecond) // number of seconds for which new questions don't pick this server
@@ -66,14 +71,34 @@ extern "C" {
// then use the default value of 30 seconds
#define DEFAULT_UDNS_TIMEOUT 30 // in seconds
-// For questions that are validating responses (q->ValidatingResponse == 1), use 10 seconds
-// which accomodates two DNS servers and two queries per DNS server.
-#define DEFAULT_UDNSSEC_TIMEOUT 10 // in seconds
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
+// Push notification structures
+struct mDNS_DNSPushNotificationServer
+{
+ dso_connect_state_t *connectInfo; // DSO Connection state information
+ dso_state_t *connection; // DNS Stateful Operations/TCP Connection pointer, might be null.
+ mDNSu32 numberOfQuestions; // Number of questions for this server
+ DNSPushServer_ConnectState connectState; // Current status of connection attempt to this server
+ mDNSs32 lastDisconnect; // Last time we got a disconnect, used to avoid constant reconnects
+ domainname serverName; // The hostname returned by the _dns-push-tls._tcp.<zone> SRV lookup
+ mDNSIPPort port; // The port from the SRV lookup
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ mdns_dns_service_t dnsservice;
+#else
+ DNSServer *qDNSServer; // DNS server stolen from the question that created this server structure.
+#endif
+ mDNS *m;
+ DNSPushNotificationServer *next;
+} ;
-// If we are sending queries with EDNS0/DO option and we have no indications that the server
-// is DNSSEC aware and we have already reached MAX_DNSSEC_RETRANSMISSIONS, we disable
-// validation (for optional case only) for any questions that uses this server
-#define MAX_DNSSEC_RETRANSMISSIONS 3
+struct mDNS_DNSPushNotificationZone
+{
+ domainname zoneName;
+ DNSPushNotificationServer *server; // DNS Push Notification Servers for this zone
+ mDNSu32 numberOfQuestions; // Number of questions for this zone
+ DNSPushNotificationZone *next;
+} ;
+#endif
// Entry points into unicast-specific routines
@@ -81,10 +106,15 @@ extern void LLQGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneInfo)
extern void startLLQHandshake(mDNS *m, DNSQuestion *q);
extern void sendLLQRefresh(mDNS *m, DNSQuestion *q);
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
extern void DNSPushNotificationGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneInfo);
extern void DiscoverDNSPushNotificationServer(mDNS *m, DNSQuestion *q);
-extern void SubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q);
+extern DNSPushNotificationServer *GetConnectionToDNSPushNotificationServer(mDNS *m, DNSQuestion *q);
+extern DNSPushNotificationServer *SubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q);
extern void UnSubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q);
+extern void DNSPushReconcileConnection(mDNS *m, DNSQuestion *q);
+extern void DNSPushServerDrop(DNSPushNotificationServer *server);
+#endif
extern void SleepRecordRegistrations(mDNS *m);
@@ -106,7 +136,6 @@ extern mStatus mDNS_StartNATOperation_internal(mDNS *const m, NATTraversalInfo *
extern void RecordRegistrationGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneData);
extern mStatus uDNS_DeregisterRecord(mDNS *const m, AuthRecord *const rr);
extern const domainname *GetServiceTarget(mDNS *m, AuthRecord *const rr);
-extern void uDNS_CheckCurrentQuestion(mDNS *const m);
// integer fields of msg header must be in HOST byte order before calling this routine
extern void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
@@ -128,7 +157,7 @@ extern mStatus uDNS_SetupDNSConfig(mDNS *const m);
extern void uDNS_SetupWABQueries(mDNS *const m);
extern void uDNS_StartWABQueries(mDNS *const m, int queryType);
extern void uDNS_StopWABQueries(mDNS *const m, int queryType);
-extern domainname *uDNS_GetNextSearchDomain(mDNSInterfaceID InterfaceID, mDNSs8 *searchIndex, mDNSBool ignoreDotLocal);
+extern domainname *uDNS_GetNextSearchDomain(mDNSInterfaceID InterfaceID, int *searchIndex, mDNSBool ignoreDotLocal);
extern void uDNS_RestartQuestionAsTCP(mDNS *m, DNSQuestion *const q, const mDNSAddr *const srcaddr, const mDNSIPPort srcport);
@@ -150,10 +179,14 @@ extern void uDNS_ReceiveNATPacket(mDNS *m, const mDNSInterfaceID InterfaceID, mD
extern void natTraversalHandleAddressReply(mDNS *const m, mDNSu16 err, mDNSv4Addr ExtAddr);
extern void natTraversalHandlePortMapReply(mDNS *const m, NATTraversalInfo *n, const mDNSInterfaceID InterfaceID, mDNSu16 err, mDNSIPPort extport, mDNSu32 lease, NATTProtocol protocol);
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
// DNS Push Notification
extern void SubscribeToDNSPushNotification(mDNS *m, DNSQuestion *q);
+#endif
-
+extern CacheRecord* mDNSCoreReceiveCacheCheck(mDNS *const m, const DNSMessage *const response, uDNS_LLQType LLQType,
+ const mDNSu32 slot, CacheGroup *cg,
+ CacheRecord ***cfp, mDNSInterfaceID InterfaceID);
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/contrib/mDNSResponder/mDNSPosix/PosixDaemon.c b/usr/src/contrib/mDNSResponder/mDNSPosix/PosixDaemon.c
index dd932949e7..60a6727884 100644
--- a/usr/src/contrib/mDNSResponder/mDNSPosix/PosixDaemon.c
+++ b/usr/src/contrib/mDNSResponder/mDNSPosix/PosixDaemon.c
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+/*
+ * Copyright (c) 2003-2019 Apple Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -37,6 +36,7 @@
#include <fcntl.h>
#include <pwd.h>
#include <sys/types.h>
+#include <sys/socket.h>
#if __APPLE__
#undef daemon
@@ -48,6 +48,7 @@ extern int daemon(int, int);
#include "mDNSUNP.h" // For daemon()
#include "uds_daemon.h"
#include "PlatformCommon.h"
+#include "posix_utilities.h" // For getLocalTimestamp()
#ifndef MDNSD_USER
#define MDNSD_USER "nobody"
@@ -135,9 +136,19 @@ mDNSlocal void ToggleLogPacket(void)
// Dump a little log of what we've been up to.
mDNSlocal void DumpStateLog()
{
- LogMsg("---- BEGIN STATE LOG ----");
- udsserver_info();
- LogMsg("---- END STATE LOG ----");
+ char timestamp[64]; // 64 is enough to store the UTC timestmp
+
+ mDNSu32 major_version = _DNS_SD_H / 10000;
+ mDNSu32 minor_version1 = (_DNS_SD_H - major_version * 10000) / 100;
+ mDNSu32 minor_version2 = _DNS_SD_H % 100;
+
+ getLocalTimestamp(timestamp, sizeof(timestamp));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "---- BEGIN STATE LOG ---- (%s mDNSResponder Build %d.%02d.%02d)", timestamp, major_version, minor_version1, minor_version2);
+
+ udsserver_info_dump_to_fd(STDERR_FILENO);
+
+ getLocalTimestamp(timestamp, sizeof(timestamp));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "---- END STATE LOG ---- (%s mDNSResponder Build %d.%02d.%02d)", timestamp, major_version, minor_version1, minor_version2);
}
mDNSlocal mStatus MainLoop(mDNS *m) // Loop until we quit.
@@ -207,16 +218,21 @@ int main(int argc, char **argv)
{
const struct passwd *pw = getpwnam(MDNSD_USER);
if (pw != NULL)
- setuid(pw->pw_uid);
+ {
+ if (setgid(pw->pw_gid) < 0)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "WARNING: mdnsd continuing as group root because setgid to \""MDNSD_USER"\" failed with " PUB_S, strerror(errno));
+ }
+ if (setuid(pw->pw_uid) < 0)
+ {
+ LogMsg("WARNING: mdnsd continuing as root because setuid to \""MDNSD_USER"\" failed with %s", strerror(errno));
+ }
+ }
else
-#ifdef MDNSD_NOROOT
- {
- LogMsg("WARNING: mdnsd exiting because user \""MDNSD_USER"\" does not exist");
- err = mStatus_Invalid;
- }
-#else
+ {
LogMsg("WARNING: mdnsd continuing as root because user \""MDNSD_USER"\" does not exist");
-#endif
+ }
}
if (mStatus_NoError == err)
@@ -230,7 +246,7 @@ int main(int argc, char **argv)
LogMsg("ExitCallback: udsserver_exit failed");
#if MDNS_DEBUGMSGS > 0
- printf("mDNSResponder exiting normally with %ld\n", err);
+ printf("mDNSResponder exiting normally with %d\n", err);
#endif
return err;
diff --git a/usr/src/contrib/mDNSResponder/mDNSPosix/mDNSPosix.c b/usr/src/contrib/mDNSResponder/mDNSPosix/mDNSPosix.c
index 50acd2bd4c..45e59a5728 100755
--- a/usr/src/contrib/mDNSResponder/mDNSPosix/mDNSPosix.c
+++ b/usr/src/contrib/mDNSResponder/mDNSPosix/mDNSPosix.c
@@ -1,6 +1,6 @@
-/* -*- Mode: C; tab-width: 4 -*-
+/* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*-
*
- * Copyright (c) 2002-2015 Apple Inc. All rights reserved.
+ * Copyright (c) 2002-2019 Apple Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,9 +19,8 @@
#include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
#include "DNSCommon.h"
#include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
+#include "PlatformCommon.h"
#include "dns_sd.h"
-#include "dnssec.h"
-#include "nsec.h"
#include <assert.h>
#include <stdio.h>
@@ -40,6 +39,7 @@
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h> // platform support for UTC time
+#include <ifaddrs.h>
#if USES_NETLINK
#include <asm/types.h>
@@ -57,16 +57,6 @@
// ***************************************************************************
// Structures
-// We keep a list of client-supplied event sources in PosixEventSource records
-struct PosixEventSource
-{
- mDNSPosixEventCallback Callback;
- void *Context;
- int fd;
- struct PosixEventSource *Next;
-};
-typedef struct PosixEventSource PosixEventSource;
-
// Context record for interface change callback
struct IfChangeRec
{
@@ -76,9 +66,7 @@ struct IfChangeRec
typedef struct IfChangeRec IfChangeRec;
// Note that static data is initialized to zero in (modern) C.
-static fd_set gEventFDs;
-static int gMaxFD; // largest fd in gEventFDs
-static GenLinkedList gEventSources; // linked list of PosixEventSource's
+static PosixEventSource *gEventSources; // linked list of PosixEventSource's
static sigset_t gEventSignalSet; // Signals which event loop listens for
static sigset_t gEventSignals; // Signals which were received while inside loop
@@ -92,8 +80,22 @@ static int num_pkts_accepted = 0;
static int num_pkts_rejected = 0;
// ***************************************************************************
+// Locals
+mDNSlocal void requestReadEvents(PosixEventSource *eventSource,
+ const char *taskName, mDNSPosixEventCallback callback, void *context);
+mDNSlocal mStatus stopReadOrWriteEvents(int fd, mDNSBool freeSource, mDNSBool removeSource, int flags);
+mDNSlocal void requestWriteEvents(PosixEventSource *eventSource,
+ const char *taskName, mDNSPosixEventCallback callback, void *context);
+// ***************************************************************************
// Functions
+#if MDNS_MALLOC_DEBUGGING
+mDNSexport void mDNSPlatformValidateLists(void)
+{
+ // This should validate gEventSources and any other Posix-specific stuff that gets allocated.
+}
+#endif
+
int gMDNSPlatformPosixVerboseLevel = 0;
#define PosixErrorToStatus(errNum) ((errNum) == 0 ? mStatus_NoError : mStatus_UnknownErr)
@@ -215,6 +217,70 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms
return PosixErrorToStatus(err);
}
+mDNSlocal void TCPReadCallback(int fd, void *context)
+{
+ TCPSocket *sock = context;
+ (void)fd;
+
+ if (sock->flags & kTCPSocketFlags_UseTLS)
+ {
+ // implement
+ }
+ else
+ {
+ sock->callback(sock, sock->context, mDNSfalse, sock->err);
+ }
+}
+
+mDNSlocal void tcpConnectCallback(int fd, void *context)
+{
+ TCPSocket *sock = context;
+ mDNSBool c = !sock->connected;
+ int result;
+ socklen_t len = sizeof result;
+
+ sock->connected = mDNStrue;
+
+ if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &result, &len) < 0)
+ {
+ LogInfo("ERROR: TCPConnectCallback - unable to get connect error: socket %d: Error %d (%s)",
+ sock->events.fd, result, strerror(result));
+ sock->err = mStatus_ConnFailed;
+ }
+ else
+ {
+ if (result != 0)
+ {
+ sock->err = mStatus_ConnFailed;
+ if (result == EHOSTUNREACH || result == EADDRNOTAVAIL || result == ENETDOWN)
+ {
+ LogInfo("ERROR: TCPConnectCallback - connect failed: socket %d: Error %d (%s)",
+ sock->events.fd, result, strerror(result));
+ }
+ else
+ {
+ LogMsg("ERROR: TCPConnectCallback - connect failed: socket %d: Error %d (%s)",
+ sock->events.fd, result, strerror(result));
+ }
+ }
+ else
+ {
+ // The connection succeeded.
+ sock->connected = mDNStrue;
+ // Select for read events.
+ sock->events.fd = fd;
+ requestReadEvents(&sock->events, "mDNSPosix::tcpConnectCallback", TCPReadCallback, sock);
+ }
+ }
+
+ if (sock->callback)
+ {
+ sock->callback(sock, sock->context, c, sock->err);
+ // Here sock must be assumed to be invalid, in case the callback freed it.
+ return;
+ }
+}
+
// This routine is called when the main loop detects that data is available on a socket.
mDNSlocal void SocketDataReady(mDNS *const m, PosixNetworkInterface *intf, int skt)
{
@@ -315,60 +381,314 @@ mDNSlocal void SocketDataReady(mDNS *const m, PosixNetworkInterface *intf, int s
&senderAddr, senderPort, &destAddr, MulticastDNSPort, InterfaceID);
}
-mDNSexport TCPSocket *mDNSPlatformTCPSocket(TCPSocketFlags flags, mDNSIPPort * port, mDNSBool useBackgroundTrafficClass)
+mDNSexport TCPSocket *mDNSPlatformTCPSocket(TCPSocketFlags flags, mDNSAddr_Type addrType, mDNSIPPort * port,
+ domainname *hostname, mDNSBool useBackgroundTrafficClass)
{
- (void)flags; // Unused
- (void)port; // Unused
- (void)useBackgroundTrafficClass; // Unused
- return NULL;
+ TCPSocket *sock;
+ int len = sizeof (TCPSocket);
+
+ (void)useBackgroundTrafficClass;
+
+ if (hostname)
+ {
+ len += sizeof (domainname);
+ }
+ sock = malloc(len);
+
+ if (sock == NULL)
+ {
+ LogMsg("mDNSPlatformTCPSocket: no memory for socket");
+ return NULL;
+ }
+ memset(sock, 0, sizeof *sock);
+
+ if (hostname)
+ {
+ sock->hostname = (domainname *)(sock + 1);
+ LogMsg("mDNSPlatformTCPSocket: hostname %##s", hostname->c);
+ AssignDomainName(sock->hostname, hostname);
+ }
+
+ sock->events.fd = -1;
+ if (!mDNSPosixTCPSocketSetup(&sock->events.fd, addrType, port, &sock->port))
+ {
+ if (sock->events.fd != -1) close(sock->events.fd);
+ free(sock);
+ return mDNSNULL;
+ }
+
+ // Set up the other fields in the structure.
+ sock->flags = flags;
+ sock->err = mStatus_NoError;
+ sock->setup = mDNSfalse;
+ sock->connected = mDNSfalse;
+ return sock;
}
-mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int sd)
+mDNSexport mStatus mDNSPlatformTCPSocketSetCallback(TCPSocket *sock, TCPConnectionCallback callback, void *context)
{
- (void)flags; // Unused
- (void)sd; // Unused
- return NULL;
+ sock->callback = callback;
+ sock->context = context;
+ return mStatus_NoError;
+}
+
+mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int fd)
+{
+ TCPSocket *sock;
+
+ // XXX Add!
+ if (flags & kTCPSocketFlags_UseTLS)
+ {
+ return mDNSNULL; // not supported yet.
+ }
+
+ sock = (TCPSocket *) mDNSPlatformMemAllocateClear(sizeof *sock);
+ if (!sock)
+ {
+ return mDNSNULL;
+ }
+
+ sock->events.fd = fd;
+ sock->flags = flags;
+ sock->connected = mDNStrue;
+ return sock;
+}
+
+
+mDNSlocal void tcpListenCallback(int fd, void *context)
+{
+ TCPListener *listener = context;
+ TCPSocket *sock;
+
+ sock = mDNSPosixDoTCPListenCallback(fd, listener->addressType, listener->socketFlags,
+ listener->callback, listener->context);
+ if (sock != NULL)
+ {
+ requestReadEvents(&sock->events, "mDNSPosix::tcpListenCallback", TCPReadCallback, sock);
+ }
+}
+
+mDNSexport TCPListener *mDNSPlatformTCPListen(mDNSAddr_Type addrType, mDNSIPPort *port, mDNSAddr *addr,
+ TCPSocketFlags socketFlags, mDNSBool reuseAddr, int queueLength,
+ TCPAcceptedCallback callback, void *context)
+{
+ TCPListener *ret;
+ int fd = -1;
+
+ if (!mDNSPosixTCPListen(&fd, addrType, port, addr, reuseAddr, queueLength))
+ {
+ if (fd != -1)
+ {
+ close(fd);
+ }
+ return mDNSNULL;
+ }
+
+ // Allocate a listener structure
+ ret = (TCPListener *) mDNSPlatformMemAllocateClear(sizeof *ret);
+ if (ret == NULL)
+ {
+ LogMsg("mDNSPlatformTCPListen: no memory for TCPListener struct.");
+ close(fd);
+ return mDNSNULL;
+ }
+ ret->events.fd = fd;
+ ret->callback = callback;
+ ret->context = context;
+ ret->addressType = addrType;
+ ret->socketFlags = socketFlags;
+
+ // When we get a connection, mDNSPosixListenCallback will be called, and it will invoke the
+ // callback we were passed.
+ requestReadEvents(&ret->events, "tcpListenCallback", tcpListenCallback, ret);
+ return ret;
}
mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
{
- (void)sock; // Unused
- return -1;
+ return sock->events.fd;
}
-mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, domainname *hostname, mDNSInterfaceID InterfaceID,
- TCPConnectionCallback callback, void *context)
+mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport,
+ mDNSInterfaceID InterfaceID, TCPConnectionCallback callback, void *context)
{
- (void)sock; // Unused
- (void)dst; // Unused
- (void)dstport; // Unused
- (void)hostname; // Unused
- (void)InterfaceID; // Unused
- (void)callback; // Unused
- (void)context; // Unused
- return(mStatus_UnsupportedErr);
+ int result;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ } addr;
+ socklen_t len;
+
+ sock->callback = callback;
+ sock->context = context;
+ sock->setup = mDNSfalse;
+ sock->connected = mDNSfalse;
+ sock->err = mStatus_NoError;
+
+ result = fcntl(sock->events.fd, F_GETFL, 0);
+ if (result < 0)
+ {
+ LogMsg("mDNSPlatformTCPConnect: F_GETFL failed: %s", strerror(errno));
+ return mStatus_UnknownErr;
+ }
+
+ result = fcntl(sock->events.fd, F_SETFL, result | O_NONBLOCK);
+ if (result < 0)
+ {
+ LogMsg("mDNSPlatformTCPConnect: F_SETFL failed: %s", strerror(errno));
+ return mStatus_UnknownErr;
+ }
+
+ // If we've been asked to bind to a single interface, do it. See comment in mDNSMacOSX.c for more info.
+ if (InterfaceID)
+ {
+ PosixNetworkInterface *iface = (PosixNetworkInterface *)InterfaceID;
+#if defined(SO_BINDTODEVICE)
+ result = setsockopt(sock->events.fd,
+ SOL_SOCKET, SO_BINDTODEVICE, iface->intfName, strlen(iface->intfName));
+ if (result < 0)
+ {
+ LogMsg("mDNSPlatformTCPConnect: SO_BINDTODEVICE failed on %s: %s", iface->intfName, strerror(errno));
+ return mStatus_BadParamErr;
+ }
+#else
+ if (dst->type == mDNSAddrType_IPv4)
+ {
+#if defined(IP_BOUND_IF)
+ result = setsockopt(sock->events.fd, IPPROTO_IP, IP_BOUND_IF, &iface->index, sizeof iface->index);
+ if (result < 0)
+ {
+ LogMsg("mDNSPlatformTCPConnect: IP_BOUND_IF failed on %s (%d): %s",
+ iface->intfName, iface->index, strerror(errno));
+ return mStatus_BadParamErr;
+ }
+#else
+ (void)iface;
+#endif // IP_BOUND_IF
+ }
+ else
+ { // IPv6
+#if defined(IPV6_BOUND_IF)
+ result = setsockopt(sock->events.fd, IPPROTO_IPV6, IPV6_BOUND_IF, &iface->index, sizeof iface->index);
+ if (result < 0)
+ {
+ LogMsg("mDNSPlatformTCPConnect: IP_BOUND_IF failed on %s (%d): %s",
+ iface->intfName, iface->index, strerror(errno));
+ return mStatus_BadParamErr;
+ }
+#else
+ (void)iface;
+#endif // IPV6_BOUND_IF
+ }
+#endif // SO_BINDTODEVICE
+ }
+
+ memset(&addr, 0, sizeof addr);
+ if (dst->type == mDNSAddrType_IPv4)
+ {
+ addr.sa.sa_family = AF_INET;
+ addr.sin.sin_port = dstport.NotAnInteger;
+ len = sizeof (struct sockaddr_in);
+ addr.sin.sin_addr.s_addr = dst->ip.v4.NotAnInteger;
+ }
+ else
+ {
+ addr.sa.sa_family = AF_INET6;
+ len = sizeof (struct sockaddr_in6);
+ addr.sin6.sin6_port = dstport.NotAnInteger;
+ memcpy(&addr.sin6.sin6_addr.s6_addr, &dst->ip.v6, sizeof addr.sin6.sin6_addr.s6_addr);
+ }
+#ifndef NOT_HAVE_SA_LEN
+ addr.sa.sa_len = len;
+#endif
+
+ result = connect(sock->events.fd, (struct sockaddr *)&addr, len);
+ if (result < 0)
+ {
+ if (errno == EINPROGRESS)
+ {
+ requestWriteEvents(&sock->events, "mDNSPlatformConnect", tcpConnectCallback, sock);
+ return mStatus_ConnPending;
+ }
+ if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
+ {
+ LogInfo("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)",
+ sock->events.fd, errno, strerror(errno));
+ }
+ else
+ {
+ LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s) length %d",
+ sock->events.fd, errno, strerror(errno), len);
+ }
+ return mStatus_ConnFailed;
+ }
+
+ LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
+ return mStatus_NoError;
}
mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
{
- (void)sock; // Unused
+ if (sock)
+ { // can sock really be NULL when this is called?
+ shutdown(sock->events.fd, SHUT_RDWR);
+ stopReadOrWriteEvents(sock->events.fd, mDNSfalse, mDNStrue,
+ PosixEventFlag_Read | PosixEventFlag_Write);
+ close(sock->events.fd);
+ free(sock);
+ }
}
mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool * closed)
{
- (void)sock; // Unused
- (void)buf; // Unused
- (void)buflen; // Unused
- (void)closed; // Unused
- return 0;
+ ssize_t nread;
+
+ *closed = mDNSfalse;
+ if (sock->flags & kTCPSocketFlags_UseTLS)
+ {
+ // Implement...
+ nread = -1;
+ *closed = mDNStrue;
+ } else {
+ nread = mDNSPosixReadTCP(sock->events.fd, buf, buflen, closed);
+ }
+ return nread;
+}
+
+mDNSexport mDNSBool mDNSPlatformTCPWritable(TCPSocket *sock)
+{
+ fd_set w = { 0 };
+ int nfds = sock->events.fd + 1;
+ int count;
+ struct timeval tv;
+
+ if (nfds > FD_SETSIZE)
+ {
+ LogMsg("ERROR: mDNSPlatformTCPWritable called on an fd that won't fit in an fd_set.");
+ return mDNStrue; // hope for the best?
+ }
+ FD_SET(sock->events.fd, &w);
+ tv.tv_sec = tv.tv_usec = 0;
+ count = select(nfds, NULL, &w, NULL, &tv);
+ if (count > 0)
+ {
+ return mDNStrue;
+ }
+ return mDNSfalse;
}
mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
{
- (void)sock; // Unused
- (void)msg; // Unused
- (void)len; // Unused
- return 0;
+ if (sock->flags & kTCPSocketFlags_UseTLS)
+ {
+ // implement
+ return -1;
+ }
+ else
+ {
+ return mDNSPosixWriteTCP(sock->events.fd, msg, len);
+ }
}
mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNSIPPort port)
@@ -437,12 +757,13 @@ mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNSBool setservers, mDNSBool setse
DNameListElem **BrowseDomains, mDNSBool ackConfig)
{
(void) setservers;
- if (fqdn) fqdn->c[0] = 0;
(void) setsearch;
- if (RegDomains) *RegDomains = NULL;
- if (BrowseDomains) *BrowseDomains = NULL;
(void) ackConfig;
+ if (fqdn ) fqdn->c[0] = 0;
+ if (RegDomains ) *RegDomains = NULL;
+ if (BrowseDomains) *BrowseDomains = NULL;
+
return mDNStrue;
}
@@ -502,11 +823,11 @@ mDNSexport int ParseDNSServers(mDNS *m, const char *filePath)
mDNSAddr DNSAddr;
DNSAddr.type = mDNSAddrType_IPv4;
DNSAddr.ip.v4.NotAnInteger = ina.s_addr;
- mDNS_AddDNSServer(m, NULL, mDNSInterface_Any, 0, &DNSAddr, UnicastDNSPort, kScopeNone, 0, mDNSfalse, mDNSfalse, mDNSfalse, 0, mDNStrue, mDNStrue, mDNSfalse);
+ mDNS_AddDNSServer(m, NULL, mDNSInterface_Any, 0, &DNSAddr, UnicastDNSPort, kScopeNone, 0, mDNSfalse, mDNSfalse, mDNSfalse, mDNSfalse, 0, mDNStrue, mDNStrue, mDNSfalse);
numOfServers++;
}
}
- fclose(fp);
+ fclose(fp);
return (numOfServers > 0) ? 0 : -1;
}
@@ -639,7 +960,7 @@ mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interf
// ... with a shared UDP port, if it's for multicast receiving
if (err == 0 && port.NotAnInteger)
{
- // <rdar://problem/20946253>
+ // <rdar://problem/20946253> Suggestions from Jonny Törnbom at Axis Communications
// We test for SO_REUSEADDR first, as suggested by Jonny Törnbom from Axis Communications
// Linux kernel versions 3.9 introduces support for socket option
// SO_REUSEPORT, however this is not implemented the same as on *BSD
@@ -660,12 +981,15 @@ mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interf
#endif
if (err < 0) { err = errno; perror("setsockopt - SO_REUSExxxx"); }
+#if TARGET_OS_MAC
// Enable inbound packets on IFEF_AWDL interface.
// Only done for multicast sockets, since we don't expect unicast socket operations
// on the IFEF_AWDL interface. Operation is a no-op for other interface types.
- #ifdef SO_RECV_ANYIF
+ #ifndef SO_RECV_ANYIF
+ #define SO_RECV_ANYIF 0x1104 /* unrestricted inbound processing */
+ #endif
if (setsockopt(*sktPtr, SOL_SOCKET, SO_RECV_ANYIF, &kOn, sizeof(kOn)) < 0) perror("setsockopt - SO_RECV_ANYIF");
- #endif
+#endif
}
// We want to receive destination addresses and interface identifiers.
@@ -890,8 +1214,26 @@ mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct
// And make a copy of the intfName.
if (err == 0)
{
+#ifdef LINUX
+ char *s;
+ int len;
+ s = strchr(intfName, ':');
+ if (s != NULL)
+ {
+ len = (s - intfName) + 1;
+ }
+ else
+ {
+ len = strlen(intfName) + 1;
+ }
+ intf->intfName = malloc(len);
+ if (intf->intfName == NULL) { assert(0); err = ENOMEM; }
+ memcpy(intf->intfName, intfName, len - 1);
+ intfName[len - 1] = 0;
+#else
intf->intfName = strdup(intfName);
if (intf->intfName == NULL) { assert(0); err = ENOMEM; }
+#endif
}
if (err == 0)
@@ -903,6 +1245,7 @@ mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct
//LogMsg("SetupOneInterface: %#a %#a", &intf->coreIntf.ip, &intf->coreIntf.mask);
strncpy(intf->coreIntf.ifname, intfName, sizeof(intf->coreIntf.ifname));
intf->coreIntf.ifname[sizeof(intf->coreIntf.ifname)-1] = 0;
+
intf->coreIntf.Advertise = m->AdvertiseLocalAddresses;
intf->coreIntf.McastTxRx = mDNStrue;
@@ -970,47 +1313,56 @@ mDNSlocal int SetupInterfaceList(mDNS *const m)
{
mDNSBool foundav4 = mDNSfalse;
int err = 0;
- struct ifi_info *intfList = get_ifi_info(AF_INET, mDNStrue);
- struct ifi_info *firstLoopback = NULL;
+ struct ifaddrs *intfList;
+ struct ifaddrs *firstLoopback = NULL;
+ int firstLoopbackIndex = 0;
assert(m != NULL);
debugf("SetupInterfaceList");
- if (intfList == NULL) err = ENOENT;
-
-#if HAVE_IPV6
- if (err == 0) /* Link the IPv6 list to the end of the IPv4 list */
+ if (getifaddrs(&intfList) < 0)
{
- struct ifi_info **p = &intfList;
- while (*p) p = &(*p)->ifi_next;
- *p = get_ifi_info(AF_INET6, mDNStrue);
+ err = errno;
}
-#endif
+ if (intfList == NULL) err = ENOENT;
if (err == 0)
{
- struct ifi_info *i = intfList;
+ struct ifaddrs *i = intfList;
while (i)
{
- if ( ((i->ifi_addr->sa_family == AF_INET)
+ if ( i->ifa_addr != NULL &&
+ ((i->ifa_addr->sa_family == AF_INET)
#if HAVE_IPV6
- || (i->ifi_addr->sa_family == AF_INET6)
+ || (i->ifa_addr->sa_family == AF_INET6)
#endif
- ) && (i->ifi_flags & IFF_UP) && !(i->ifi_flags & IFF_POINTOPOINT))
+ ) && (i->ifa_flags & IFF_UP) && !(i->ifa_flags & IFF_POINTOPOINT))
{
- if (i->ifi_flags & IFF_LOOPBACK)
+ int ifIndex = if_nametoindex(i->ifa_name);
+ if (ifIndex == 0)
+ {
+ continue;
+ }
+ if (i->ifa_flags & IFF_LOOPBACK)
{
if (firstLoopback == NULL)
+ {
firstLoopback = i;
+ firstLoopbackIndex = ifIndex;
+ }
}
else
{
- if (SetupOneInterface(m, i->ifi_addr, i->ifi_netmask, i->ifi_name, i->ifi_index) == 0)
- if (i->ifi_addr->sa_family == AF_INET)
+ if (SetupOneInterface(m, i->ifa_addr, i->ifa_netmask, i->ifa_name, ifIndex) == 0)
+ {
+ if (i->ifa_addr->sa_family == AF_INET)
+ {
foundav4 = mDNStrue;
+ }
+ }
}
}
- i = i->ifi_next;
+ i = i->ifa_next;
}
// If we found no normal interfaces but we did find a loopback interface, register the
@@ -1019,11 +1371,14 @@ mDNSlocal int SetupInterfaceList(mDNS *const m)
// In the interim, we skip loopback interface only if we found at least one v4 interface to use
// if ((m->HostInterfaces == NULL) && (firstLoopback != NULL))
if (!foundav4 && firstLoopback)
- (void) SetupOneInterface(m, firstLoopback->ifi_addr, firstLoopback->ifi_netmask, firstLoopback->ifi_name, firstLoopback->ifi_index);
+ {
+ (void)SetupOneInterface(m, firstLoopback->ifa_addr, firstLoopback->ifa_netmask, firstLoopback->ifa_name,
+ firstLoopbackIndex);
+ }
}
// Clean up.
- if (intfList != NULL) free_ifi_info(intfList);
+ if (intfList != NULL) freeifaddrs(intfList);
// Clean up any interfaces that have been hanging around on the RecentInterfaces list for more than a minute
PosixNetworkInterface **ri = &gRecentInterfaces;
@@ -1229,7 +1584,7 @@ mDNSlocal mDNSu32 ProcessRoutingNotification(int sd)
#endif // USES_NETLINK
// Called when data appears on interface change notification socket
-mDNSlocal void InterfaceChangeCallback(int fd, short filter, void *context)
+mDNSlocal void InterfaceChangeCallback(int fd, void *context)
{
IfChangeRec *pChgRec = (IfChangeRec*) context;
fd_set readFDs;
@@ -1237,7 +1592,6 @@ mDNSlocal void InterfaceChangeCallback(int fd, short filter, void *context)
struct timeval zeroTimeout = { 0, 0 };
(void)fd; // Unused
- (void)filter; // Unused
FD_ZERO(&readFDs);
FD_SET(pChgRec->NotifySD, &readFDs);
@@ -1261,7 +1615,7 @@ mDNSlocal mStatus WatchForInterfaceChange(mDNS *const m)
mStatus err;
IfChangeRec *pChgRec;
- pChgRec = (IfChangeRec*) mDNSPlatformMemAllocate(sizeof *pChgRec);
+ pChgRec = (IfChangeRec*) mDNSPlatformMemAllocateClear(sizeof *pChgRec);
if (pChgRec == NULL)
return mStatus_NoMemoryErr;
@@ -1269,6 +1623,8 @@ mDNSlocal mStatus WatchForInterfaceChange(mDNS *const m)
err = OpenIfNotifySocket(&pChgRec->NotifySD);
if (err == 0)
err = mDNSPosixAddFDToEventLoop(pChgRec->NotifySD, InterfaceChangeCallback, pChgRec);
+ if (err)
+ mDNSPlatformMemFree(pChgRec);
return err;
}
@@ -1412,13 +1768,6 @@ mDNSexport void mDNSPlatformUnlock (const mDNS *const m)
#pragma mark ***** Strings
#endif
-// mDNS core calls this routine to copy C strings.
-// On the Posix platform this maps directly to the ANSI C strcpy.
-mDNSexport void mDNSPlatformStrCopy(void *dst, const void *src)
-{
- strcpy((char *)dst, (const char *)src);
-}
-
mDNSexport mDNSu32 mDNSPlatformStrLCopy(void *dst, const void *src, mDNSu32 len)
{
#if HAVE_STRLCPY
@@ -1474,31 +1823,6 @@ mDNSexport void mDNSPlatformQsort(void *base, int nel, int width, int (*compar)(
(void)qsort(base, nel, width, compar);
}
-// DNSSEC stub functions
-mDNSexport void VerifySignature(mDNS *const m, DNSSECVerifier *dv, DNSQuestion *q)
-{
- (void)m;
- (void)dv;
- (void)q;
-}
-
-mDNSexport mDNSBool AddNSECSForCacheRecord(mDNS *const m, CacheRecord *crlist, CacheRecord *negcr, mDNSu8 rcode)
-{
- (void)m;
- (void)crlist;
- (void)negcr;
- (void)rcode;
- return mDNSfalse;
-}
-
-mDNSexport void BumpDNSSECStats(mDNS *const m, DNSSECStatsAction action, DNSSECStatsType type, mDNSu32 value)
-{
- (void)m;
- (void)action;
- (void)type;
- (void)value;
-}
-
// Proxy stub functions
mDNSexport mDNSu8 *DNSProxySetAttributes(DNSQuestion *q, DNSMessageHeader *h, DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *limit)
{
@@ -1523,18 +1847,21 @@ mDNSexport void DNSProxyTerminate(void)
// mDNS core calls this routine to clear blocks of memory.
// On the Posix platform this is a simple wrapper around ANSI C memset.
-mDNSexport void mDNSPlatformMemZero(void *dst, mDNSu32 len)
+mDNSexport void mDNSPlatformMemZero(void *dst, mDNSu32 len)
{
memset(dst, 0, len);
}
-mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(malloc(len)); }
-mDNSexport void mDNSPlatformMemFree (void *mem) { free(mem); }
+#if !MDNS_MALLOC_DEBUGGING
+mDNSexport void *mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSPlatformMemAllocate", len)); }
+mDNSexport void *mDNSPlatformMemAllocateClear(mDNSu32 len) { return(callocL(name, len)); }
+mDNSexport void mDNSPlatformMemFree (void *mem) { freeL("mDNSPlatformMemFree", mem); }
+#endif
#if _PLATFORM_HAS_STRONG_PRNG_
mDNSexport mDNSu32 mDNSPlatformRandomNumber(void)
{
- return(arc4random());
+ return(arc4random());
}
#else
mDNSexport mDNSu32 mDNSPlatformRandomSeed(void)
@@ -1557,15 +1884,18 @@ mDNSexport mStatus mDNSPlatformTimeInit(void)
mDNSexport mDNSs32 mDNSPlatformRawTime()
{
- struct timeval tv;
- gettimeofday(&tv, NULL);
- // tv.tv_sec is seconds since 1st January 1970 (GMT, with no adjustment for daylight savings time)
- // tv.tv_usec is microseconds since the start of this second (i.e. values 0 to 999999)
- // We use the lower 22 bits of tv.tv_sec for the top 22 bits of our result
- // and we multiply tv.tv_usec by 16 / 15625 to get a value in the range 0-1023 to go in the bottom 10 bits.
+ struct timespec tm;
+ int ret = clock_gettime(CLOCK_MONOTONIC, &tm);
+ assert(ret == 0); // This call will only fail if the number of seconds does not fit in an object of type time_t.
+
+ // tm.tv_sec is seconds since some unspecified starting point (it is usually the system start up time)
+ // tm.tv_nsec is nanoseconds since the start of this second (i.e. values 0 to 999999999)
+ // We use the lower 22 bits of tm.tv_sec for the top 22 bits of our result
+ // and we multiply tm.tv_nsec by 2 / 1953125 to get a value in the range 0-1023 to go in the bottom 10 bits.
// This gives us a proper modular (cyclic) counter that has a resolution of roughly 1ms (actually 1/1024 second)
// and correctly cycles every 2^22 seconds (4194304 seconds = approx 48 days).
- return((tv.tv_sec << 10) | (tv.tv_usec * 16 / 15625));
+
+ return ((tm.tv_sec << 10) | (tm.tv_nsec * 2 / 1953125));
}
mDNSexport mDNSs32 mDNSPlatformUTC(void)
@@ -1687,29 +2017,48 @@ mDNSlocal void mDNSPosixAddToFDSet(int *nfds, fd_set *readfds, int s)
FD_SET(s, readfds);
}
-mDNSexport void mDNSPosixGetFDSet(mDNS *m, int *nfds, fd_set *readfds, struct timeval *timeout)
+mDNSexport void mDNSPosixGetFDSetForSelect(mDNS *m, int *nfds, fd_set *readfds, fd_set *writefds)
{
- mDNSs32 ticks;
- struct timeval interval;
-
- // 1. Call mDNS_Execute() to let mDNSCore do what it needs to do
- mDNSs32 nextevent = mDNS_Execute(m);
+ int numFDs = *nfds;
+ PosixEventSource *iSource;
// 2. Build our list of active file descriptors
PosixNetworkInterface *info = (PosixNetworkInterface *)(m->HostInterfaces);
- if (m->p->unicastSocket4 != -1) mDNSPosixAddToFDSet(nfds, readfds, m->p->unicastSocket4);
+ if (m->p->unicastSocket4 != -1) mDNSPosixAddToFDSet(&numFDs, readfds, m->p->unicastSocket4);
#if HAVE_IPV6
- if (m->p->unicastSocket6 != -1) mDNSPosixAddToFDSet(nfds, readfds, m->p->unicastSocket6);
+ if (m->p->unicastSocket6 != -1) mDNSPosixAddToFDSet(&numFDs, readfds, m->p->unicastSocket6);
#endif
while (info)
{
- if (info->multicastSocket4 != -1) mDNSPosixAddToFDSet(nfds, readfds, info->multicastSocket4);
+ if (info->multicastSocket4 != -1) mDNSPosixAddToFDSet(&numFDs, readfds, info->multicastSocket4);
#if HAVE_IPV6
- if (info->multicastSocket6 != -1) mDNSPosixAddToFDSet(nfds, readfds, info->multicastSocket6);
+ if (info->multicastSocket6 != -1) mDNSPosixAddToFDSet(&numFDs, readfds, info->multicastSocket6);
#endif
info = (PosixNetworkInterface *)(info->coreIntf.next);
}
+ // Copy over the event fds. We have to do it this way because client-provided event loops expect
+ // to initialize their FD sets first and then call mDNSPosixGetFDSet()
+ for (iSource = gEventSources; iSource; iSource = iSource->next)
+ {
+ if (iSource->readCallback != NULL)
+ FD_SET(iSource->fd, readfds);
+ if (iSource->writeCallback != NULL)
+ FD_SET(iSource->fd, writefds);
+ if (numFDs <= iSource->fd)
+ numFDs = iSource->fd + 1;
+ }
+ *nfds = numFDs;
+}
+
+mDNSexport void mDNSPosixGetNextDNSEventTime(mDNS *m, struct timeval *timeout)
+{
+ mDNSs32 ticks;
+ struct timeval interval;
+
+ // 1. Call mDNS_Execute() to let mDNSCore do what it needs to do
+ mDNSs32 nextevent = mDNS_Execute(m);
+
// 3. Calculate the time remaining to the next scheduled event (in struct timeval format)
ticks = nextevent - mDNS_TimeNow(m);
if (ticks < 1) ticks = 1;
@@ -1722,9 +2071,16 @@ mDNSexport void mDNSPosixGetFDSet(mDNS *m, int *nfds, fd_set *readfds, struct ti
*timeout = interval;
}
-mDNSexport void mDNSPosixProcessFDSet(mDNS *const m, fd_set *readfds)
+mDNSexport void mDNSPosixGetFDSet(mDNS *m, int *nfds, fd_set *readfds, fd_set *writefds, struct timeval *timeout)
+{
+ mDNSPosixGetNextDNSEventTime(m, timeout);
+ mDNSPosixGetFDSetForSelect(m, nfds, readfds, writefds);
+}
+
+mDNSexport void mDNSPosixProcessFDSet(mDNS *const m, fd_set *readfds, fd_set *writefds)
{
PosixNetworkInterface *info;
+ PosixEventSource *iSource;
assert(m != NULL);
assert(readfds != NULL);
info = (PosixNetworkInterface *)(m->HostInterfaces);
@@ -1758,67 +2114,151 @@ mDNSexport void mDNSPosixProcessFDSet(mDNS *const m, fd_set *readfds)
#endif
info = (PosixNetworkInterface *)(info->coreIntf.next);
}
-}
-
-// update gMaxFD
-mDNSlocal void DetermineMaxEventFD(void)
-{
- PosixEventSource *iSource;
- gMaxFD = 0;
- for (iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
- if (gMaxFD < iSource->fd)
- gMaxFD = iSource->fd;
+ // Now process routing socket events, discovery relay events and anything else of that ilk.
+ for (iSource = gEventSources; iSource; iSource = iSource->next)
+ {
+ if (iSource->readCallback != NULL && FD_ISSET(iSource->fd, readfds))
+ {
+ iSource->readCallback(iSource->fd, iSource->readContext);
+ break; // in case callback removed elements from gEventSources
+ }
+ else if (iSource->writeCallback != NULL && FD_ISSET(iSource->fd, writefds))
+ {
+ mDNSPosixEventCallback writeCallback = iSource->writeCallback;
+ // Write events are one-shot: to get another event, the consumer has to put in a new request.
+ // We reset this before calling the callback just in case the callback requests another write
+ // callback, or deletes the event context from the list.
+ iSource->writeCallback = NULL;
+ writeCallback(iSource->fd, iSource->writeContext);
+ break; // in case callback removed elements from gEventSources
+ }
+ }
}
-// Add a file descriptor to the set that mDNSPosixRunEventLoopOnce() listens to.
-mStatus mDNSPosixAddFDToEventLoop(int fd, mDNSPosixEventCallback callback, void *context)
-{
- PosixEventSource *newSource;
+mDNSu32 mDNSPlatformEventContextSize = sizeof (PosixEventSource);
- if (gEventSources.LinkOffset == 0)
- InitLinkedList(&gEventSources, offsetof(PosixEventSource, Next));
+mDNSlocal void requestIOEvents(PosixEventSource *newSource, const char *taskName,
+ mDNSPosixEventCallback callback, void *context, int flag)
+{
+ PosixEventSource **epp = &gEventSources;
- if (fd >= (int) FD_SETSIZE || fd < 0)
- return mStatus_UnsupportedErr;
+ if (newSource->fd >= (int) FD_SETSIZE || newSource->fd < 0)
+ {
+ LogMsg("requestIOEvents called with fd %d > FD_SETSIZE %d.", newSource->fd, FD_SETSIZE);
+ assert(0);
+ }
if (callback == NULL)
- return mStatus_BadParamErr;
-
- newSource = (PosixEventSource*) malloc(sizeof *newSource);
- if (NULL == newSource)
- return mStatus_NoMemoryErr;
+ {
+ LogMsg("requestIOEvents called no callback.", newSource->fd, FD_SETSIZE);
+ assert(0);
+ }
- newSource->Callback = callback;
- newSource->Context = context;
- newSource->fd = fd;
+ // See if this event context is already on the list; if it is, no need to scan the list.
+ if (!(newSource->flags & PosixEventFlag_OnList))
+ {
+ while (*epp)
+ {
+ // This should never happen.
+ if (newSource == *epp)
+ {
+ LogMsg("Event context marked not on list but is on list.");
+ assert(0);
+ }
+ epp = &(*epp)->next;
+ }
+ if (*epp == NULL)
+ {
+ *epp = newSource;
+ newSource->next = NULL;
+ newSource->flags = PosixEventFlag_OnList;
+ }
+ }
- AddToTail(&gEventSources, newSource);
- FD_SET(fd, &gEventFDs);
+ if (flag & PosixEventFlag_Read)
+ {
+ newSource->readCallback = callback;
+ newSource->readContext = context;
+ newSource->flags |= PosixEventFlag_Read;
+ newSource->readTaskName = taskName;
+ }
+ if (flag & PosixEventFlag_Write)
+ {
+ newSource->writeCallback = callback;
+ newSource->writeContext = context;
+ newSource->flags |= PosixEventFlag_Write;
+ newSource->writeTaskName = taskName;
+ }
+}
- DetermineMaxEventFD();
+mDNSlocal void requestReadEvents(PosixEventSource *eventSource,
+ const char *taskName, mDNSPosixEventCallback callback, void *context)
+{
+ requestIOEvents(eventSource, taskName, callback, context, PosixEventFlag_Read);
+}
- return mStatus_NoError;
+mDNSlocal void requestWriteEvents(PosixEventSource *eventSource,
+ const char *taskName, mDNSPosixEventCallback callback, void *context)
+{
+ requestIOEvents(eventSource, taskName, callback, context, PosixEventFlag_Write);
}
// Remove a file descriptor from the set that mDNSPosixRunEventLoopOnce() listens to.
-mStatus mDNSPosixRemoveFDFromEventLoop(int fd)
+mDNSlocal mStatus stopReadOrWriteEvents(int fd, mDNSBool freeContext, mDNSBool removeContext, int flags)
{
- PosixEventSource *iSource;
+ PosixEventSource *iSource, **epp = &gEventSources;
- for (iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
+ while (*epp)
{
+ iSource = *epp;
if (fd == iSource->fd)
{
- FD_CLR(fd, &gEventFDs);
- RemoveFromList(&gEventSources, iSource);
- free(iSource);
- DetermineMaxEventFD();
+ if (flags & PosixEventFlag_Read)
+ {
+ iSource->readCallback = NULL;
+ iSource->readContext = NULL;
+ }
+ if (flags & PosixEventFlag_Write)
+ {
+ iSource->writeCallback = NULL;
+ iSource->writeContext = NULL;
+ }
+ if (iSource->writeCallback == NULL && iSource->readCallback == NULL)
+ {
+ if (removeContext || freeContext)
+ *epp = iSource->next;
+ if (freeContext)
+ free(iSource);
+ }
return mStatus_NoError;
}
+ epp = &(*epp)->next;
}
return mStatus_NoSuchNameErr;
}
+// Some of the mDNSPosix client code relies on being able to add FDs to the event loop without
+// providing storage for the event-related info. mDNSPosixAddFDToEventLoop and
+// mDNSPosixRemoveFDFromEventLoop handle the event structure storage automatically.
+mStatus mDNSPosixAddFDToEventLoop(int fd, mDNSPosixEventCallback callback, void *context)
+{
+ PosixEventSource *newSource;
+
+ newSource = (PosixEventSource*) malloc(sizeof *newSource);
+ if (NULL == newSource)
+ return mStatus_NoMemoryErr;
+ memset(newSource, 0, sizeof *newSource);
+ newSource->fd = fd;
+
+ requestReadEvents(newSource, "mDNSPosixAddFDToEventLoop", callback, context);
+ return mStatus_NoError;
+}
+
+mStatus mDNSPosixRemoveFDFromEventLoop(int fd)
+{
+ return stopReadOrWriteEvents(fd, mDNStrue, mDNStrue, PosixEventFlag_Read | PosixEventFlag_Write);
+}
+
// Simply note the received signal in gEventSignals.
mDNSlocal void NoteSignal(int signum)
{
@@ -1860,34 +2300,39 @@ mStatus mDNSPosixIgnoreSignalInEventLoop(int signum)
mStatus mDNSPosixRunEventLoopOnce(mDNS *m, const struct timeval *pTimeout,
sigset_t *pSignalsReceived, mDNSBool *pDataDispatched)
{
- fd_set listenFDs = gEventFDs;
- int fdMax = 0, numReady;
+ fd_set listenFDs;
+ fd_set writeFDs;
+ int numFDs = 0, numReady;
struct timeval timeout = *pTimeout;
- // Include the sockets that are listening to the wire in our select() set
- mDNSPosixGetFDSet(m, &fdMax, &listenFDs, &timeout); // timeout may get modified
- if (fdMax < gMaxFD)
- fdMax = gMaxFD;
+ // 1. Set up the fd_set as usual here.
+ // This example client has no file descriptors of its own,
+ // but a real application would call FD_SET to add them to the set here
+ FD_ZERO(&listenFDs);
+ FD_ZERO(&writeFDs);
+
+ // 2. Set up the timeout.
+ mDNSPosixGetNextDNSEventTime(m, &timeout);
- numReady = select(fdMax + 1, &listenFDs, (fd_set*) NULL, (fd_set*) NULL, &timeout);
+ // Include the sockets that are listening to the wire in our select() set
+ mDNSPosixGetFDSetForSelect(m, &numFDs, &listenFDs, &writeFDs);
+ numReady = select(numFDs, &listenFDs, &writeFDs, (fd_set*) NULL, &timeout);
- // If any data appeared, invoke its callback
if (numReady > 0)
{
- PosixEventSource *iSource;
-
- (void) mDNSPosixProcessFDSet(m, &listenFDs); // call this first to process wire data for clients
-
- for (iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
- {
- if (FD_ISSET(iSource->fd, &listenFDs))
- {
- iSource->Callback(iSource->fd, 0, iSource->Context);
- break; // in case callback removed elements from gEventSources
- }
- }
+ mDNSPosixProcessFDSet(m, &listenFDs, &writeFDs);
*pDataDispatched = mDNStrue;
}
+ else if (numReady < 0)
+ {
+ if (errno != EINTR) {
+ // This should never happen, represents a coding error, and is not recoverable, since
+ // we'll just sit here spinning and never receive another event. The usual reason for
+ // it to happen is that an FD was closed but not removed from the event list.
+ LogMsg("select failed: %s", strerror(errno));
+ abort();
+ }
+ }
else
*pDataDispatched = mDNSfalse;
diff --git a/usr/src/contrib/mDNSResponder/mDNSPosix/mDNSPosix.h b/usr/src/contrib/mDNSResponder/mDNSPosix/mDNSPosix.h
index ca60d806ab..01d7e96805 100755
--- a/usr/src/contrib/mDNSResponder/mDNSPosix/mDNSPosix.h
+++ b/usr/src/contrib/mDNSResponder/mDNSPosix/mDNSPosix.h
@@ -1,4 +1,4 @@
-/* -*- Mode: C; tab-width: 4 -*-
+/* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*-
*
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
@@ -35,7 +35,7 @@ typedef struct PosixNetworkInterface PosixNetworkInterface;
struct PosixNetworkInterface
{
- NetworkInterfaceInfo coreIntf; // MUST be the first element in this structure
+ NetworkInterfaceInfo coreIntf; // MUST be the first element in this structure
mDNSs32 LastSeen;
const char * intfName;
PosixNetworkInterface * aliasIntf;
@@ -57,21 +57,76 @@ struct mDNS_PlatformSupport_struct
#endif
};
+// We keep a list of client-supplied event sources in PosixEventSource records
+// Add a file descriptor to the set that mDNSPosixRunEventLoopOnce() listens to.
+#define PosixEventFlag_OnList 1
+#define PosixEventFlag_Read 2
+#define PosixEventFlag_Write 4
+
+typedef void (*mDNSPosixEventCallback)(int fd, void *context);
+struct PosixEventSource
+{
+ struct PosixEventSource *next;
+ mDNSPosixEventCallback readCallback;
+ mDNSPosixEventCallback writeCallback;
+ const char *readTaskName;
+ const char *writeTaskName;
+ void *readContext;
+ void *writeContext;
+ int fd;
+ unsigned flags;
+};
+typedef struct PosixEventSource PosixEventSource;
+
+struct TCPSocket_struct
+{
+ mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with mDNSIPPort
+ TCPSocketFlags flags; // MUST BE SECOND FIELD -- mDNSCore expects every TCPSocket_struct have TCPSocketFlags flags after mDNSIPPort
+ TCPConnectionCallback callback;
+ PosixEventSource events;
+ // SSL context goes here.
+ domainname *hostname;
+ mDNSAddr remoteAddress;
+ mDNSIPPort remotePort;
+ void *context;
+ mDNSBool setup;
+ mDNSBool connected;
+ mStatus err;
+};
+
+struct TCPListener_struct
+{
+ TCPAcceptedCallback callback;
+ PosixEventSource events;
+ void *context;
+ mDNSAddr_Type addressType;
+ TCPSocketFlags socketFlags;
+};
+
#define uDNS_SERVERS_FILE "/etc/resolv.conf"
extern int ParseDNSServers(mDNS *m, const char *filePath);
extern mStatus mDNSPlatformPosixRefreshInterfaceList(mDNS *const m);
// See comment in implementation.
+// Get the next upcoming mDNS (or DNS) event time as a posix timeval that can be passed to select.
+// This will only update timeout if the next mDNS event is sooner than the value that was passed.
+// Therefore, use { FutureTime, 0 } as an initializer if no other timer events are being managed.
+extern void mDNSPosixGetNextDNSEventTime(mDNS *m, struct timeval *timeout);
+
+// Returns all the FDs that the posix I/O event system expects to be passed to select.
+extern void mDNSPosixGetFDSetForSelect(mDNS *m, int *nfds, fd_set *readfds, fd_set *writefds);
+
// Call mDNSPosixGetFDSet before calling select(), to update the parameters
// as may be necessary to meet the needs of the mDNSCore code.
// The timeout pointer MUST NOT be NULL.
// Set timeout->tv_sec to FutureTime if you want to have effectively no timeout
// After calling mDNSPosixGetFDSet(), call select(nfds, &readfds, NULL, NULL, &timeout); as usual
// After select() returns, call mDNSPosixProcessFDSet() to let mDNSCore do its work
-extern void mDNSPosixGetFDSet(mDNS *m, int *nfds, fd_set *readfds, struct timeval *timeout);
-extern void mDNSPosixProcessFDSet(mDNS *const m, fd_set *readfds);
+// mDNSPosixGetFDSet simply calls mDNSPosixGetNextDNSEventTime and then mDNSPosixGetFDSetForSelect.
+extern void mDNSPosixGetFDSet(mDNS *m, int *nfds, fd_set *readfds, fd_set *writefds, struct timeval *timeout);
-typedef void (*mDNSPosixEventCallback)(int fd, short filter, void *context);
+
+extern void mDNSPosixProcessFDSet(mDNS *const m, fd_set *readfds, fd_set *writefds);
extern mStatus mDNSPosixAddFDToEventLoop( int fd, mDNSPosixEventCallback callback, void *context);
extern mStatus mDNSPosixRemoveFDFromEventLoop( int fd);
@@ -79,6 +134,10 @@ extern mStatus mDNSPosixListenForSignalInEventLoop( int signum);
extern mStatus mDNSPosixIgnoreSignalInEventLoop( int signum);
extern mStatus mDNSPosixRunEventLoopOnce( mDNS *m, const struct timeval *pTimeout, sigset_t *pSignalsReceived, mDNSBool *pDataDispatched);
+extern mStatus mDNSPosixListenForSignalInEventLoop( int signum);
+extern mStatus mDNSPosixIgnoreSignalInEventLoop( int signum);
+extern mStatus mDNSPosixRunEventLoopOnce( mDNS *m, const struct timeval *pTimeout, sigset_t *pSignalsReceived, mDNSBool *pDataDispatched);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/contrib/mDNSResponder/mDNSPosix/mDNSUNP.h b/usr/src/contrib/mDNSResponder/mDNSPosix/mDNSUNP.h
index 2b36ceb042..1cead0975c 100755
--- a/usr/src/contrib/mDNSResponder/mDNSPosix/mDNSUNP.h
+++ b/usr/src/contrib/mDNSResponder/mDNSPosix/mDNSUNP.h
@@ -44,14 +44,6 @@ extern "C" {
typedef unsigned int socklen_t;
#endif
-#if !defined(_SS_MAXSIZE)
-#if HAVE_IPV6
-#define sockaddr_storage sockaddr_in6
-#else
-#define sockaddr_storage sockaddr
-#endif // HAVE_IPV6
-#endif // !defined(_SS_MAXSIZE)
-
#ifndef NOT_HAVE_SA_LEN
#define GET_SA_LEN(X) (sizeof(struct sockaddr) > ((struct sockaddr*)&(X))->sa_len ? \
sizeof(struct sockaddr) : ((struct sockaddr*)&(X))->sa_len )
@@ -96,17 +88,6 @@ struct ifi_info {
struct ifi_info *ifi_next; /* next of these structures */
};
-#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 doaliases);
-#endif
-
-#if defined(AF_INET6) && HAVE_IPV6
-#define INET6_ADDRSTRLEN 46 /*Maximum length of IPv6 address */
-#endif
-
-
-
#define IFI_ALIAS 1 /* ifi_addr is an alias */
/* From the text (Stevens, section 16.6): */
@@ -117,7 +98,11 @@ extern struct ifi_info *get_ifi_info(int family, int doaliases);
/* 'The free_ifi_info function, which takes a pointer that was */
/* returned by get_ifi_info and frees all the dynamic memory.' */
-extern void free_ifi_info(struct ifi_info *);
+extern void free_ifi_info(struct ifi_info *);
+
+#if defined(AF_INET6) && HAVE_IPV6
+#define INET6_ADDRSTRLEN 46 /*Maximum length of IPv6 address */
+#endif
#ifdef NOT_HAVE_DAEMON
extern int daemon(int nochdir, int noclose);
diff --git a/usr/src/contrib/mDNSResponder/mDNSPosix/posix_utilities.c b/usr/src/contrib/mDNSResponder/mDNSPosix/posix_utilities.c
new file mode 100644
index 0000000000..89eca5b098
--- /dev/null
+++ b/usr/src/contrib/mDNSResponder/mDNSPosix/posix_utilities.c
@@ -0,0 +1,28 @@
+//
+// posix_utilities.c
+// mDNSResponder
+//
+// Copyright (c) 2019 Apple Inc. All rights reserved.
+//
+
+#include "posix_utilities.h"
+#include "mDNSEmbeddedAPI.h"
+#include <stdlib.h> // for NULL
+#include <stdio.h> // for snprintf
+#include <time.h>
+#include <sys/time.h> // for gettimeofday
+
+mDNSexport void getLocalTimestamp(char * const buffer, mDNSu32 buffer_len)
+{
+ struct timeval now;
+ struct tm local_time;
+ char date_time_str[32];
+ char time_zone_str[32];
+
+ gettimeofday(&now, NULL);
+ localtime_r(&now.tv_sec, &local_time);
+
+ strftime(date_time_str, sizeof(date_time_str), "%F %T", &local_time);
+ strftime(time_zone_str, sizeof(time_zone_str), "%z", &local_time);
+ snprintf(buffer, buffer_len, "%s.%06lu%s", date_time_str, (unsigned long)now.tv_usec, time_zone_str);
+}
diff --git a/usr/src/contrib/mDNSResponder/mDNSPosix/posix_utilities.h b/usr/src/contrib/mDNSResponder/mDNSPosix/posix_utilities.h
new file mode 100644
index 0000000000..2eff6f384b
--- /dev/null
+++ b/usr/src/contrib/mDNSResponder/mDNSPosix/posix_utilities.h
@@ -0,0 +1,16 @@
+//
+// posix_utilities.h
+// mDNSResponder
+//
+// Copyright (c) 2019 Apple Inc. All rights reserved.
+//
+
+#ifndef posix_utilities_h
+#define posix_utilities_h
+
+#include "mDNSEmbeddedAPI.h"
+
+// timestamp format: "2008-08-08 20:00:00.000000+0800", a 64-byte buffer is enough to store the result
+extern void getLocalTimestamp(char * const buffer, mDNSu32 buffer_len);
+
+#endif /* posix_utilities_h */
diff --git a/usr/src/contrib/mDNSResponder/mDNSShared/ClientRequests.c b/usr/src/contrib/mDNSResponder/mDNSShared/ClientRequests.c
new file mode 100644
index 0000000000..4ea8101b64
--- /dev/null
+++ b/usr/src/contrib/mDNSResponder/mDNSShared/ClientRequests.c
@@ -0,0 +1,1068 @@
+/*
+ * Copyright (c) 2018-2020 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ClientRequests.h"
+
+#include "DNSCommon.h"
+#include "uDNS.h"
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+#include "QuerierSupport.h"
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+#include "D2D.h"
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
+#include "mDNSMacOSX.h"
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNREADY_INTERFACES)
+#include <dispatch/dispatch.h>
+#include <net/if.h>
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
+#include <WebFilterDNS/WebFilterDNS.h>
+
+int WCFIsServerRunning(WCFConnection *conn) __attribute__((weak_import));
+int WCFNameResolvesToAddr(WCFConnection *conn, char* domainName, struct sockaddr* address, uid_t userid) __attribute__((weak_import));
+int WCFNameResolvesToName(WCFConnection *conn, char* fromName, char* toName, uid_t userid) __attribute__((weak_import));
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+#include "dnssec_v2.h"
+#endif
+
+#define RecordTypeIsAddress(TYPE) (((TYPE) == kDNSType_A) || ((TYPE) == kDNSType_AAAA))
+
+extern mDNS mDNSStorage;
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
+extern domainname ActiveDirectoryPrimaryDomain;
+#endif
+
+// Normally we append search domains only for queries with a single label that are not fully qualified. This can be
+// overridden to apply search domains for queries (that are not fully qualified) with any number of labels e.g., moon,
+// moon.cs, moon.cs.be, etc. - Mohan
+mDNSBool AlwaysAppendSearchDomains = mDNSfalse;
+
+// Control enabling optimistic DNS - Phil
+mDNSBool EnableAllowExpired = mDNStrue;
+
+
+typedef struct
+{
+ mDNSu32 requestID;
+ const domainname * qname;
+ mDNSu16 qtype;
+ mDNSu16 qclass;
+ mDNSInterfaceID interfaceID;
+ mDNSs32 serviceID;
+ mDNSu32 flags;
+ mDNSBool appendSearchDomains;
+ mDNSs32 effectivePID;
+ const mDNSu8 * effectiveUUID;
+ mDNSu32 peerUID;
+ mDNSBool isInAppBrowserRequest;
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ const mDNSu8 * resolverUUID;
+ mdns_dns_service_id_t customID;
+ mDNSBool needEncryption;
+#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
+ const audit_token_t * peerAuditToken;
+ const audit_token_t * delegatorAuditToken;
+#endif
+
+} QueryRecordOpParams;
+
+mDNSlocal void QueryRecordOpParamsInit(QueryRecordOpParams *inParams)
+{
+ mDNSPlatformMemZero(inParams, (mDNSu32)sizeof(*inParams));
+ inParams->serviceID = -1;
+}
+
+mDNSlocal mStatus QueryRecordOpCreate(QueryRecordOp **outOp);
+mDNSlocal void QueryRecordOpFree(QueryRecordOp *operation);
+mDNSlocal mStatus QueryRecordOpStart(QueryRecordOp *inOp, const QueryRecordOpParams *inParams,
+ QueryRecordResultHandler inResultHandler, void *inResultContext);
+mDNSlocal void QueryRecordOpStop(QueryRecordOp *op);
+mDNSlocal mDNSBool QueryRecordOpIsMulticast(const QueryRecordOp *op);
+mDNSlocal void QueryRecordOpCallback(mDNS *m, DNSQuestion *inQuestion, const ResourceRecord *inAnswer,
+ QC_result inAddRecord);
+mDNSlocal void QueryRecordOpResetHandler(DNSQuestion *inQuestion);
+mDNSlocal mStatus QueryRecordOpStartQuestion(QueryRecordOp *inOp, DNSQuestion *inQuestion);
+mDNSlocal mStatus QueryRecordOpStopQuestion(DNSQuestion *inQuestion);
+mDNSlocal mStatus QueryRecordOpRestartUnicastQuestion(QueryRecordOp *inOp, DNSQuestion *inQuestion,
+ const domainname *inSearchDomain);
+mDNSlocal mStatus InterfaceIndexToInterfaceID(mDNSu32 inInterfaceIndex, mDNSInterfaceID *outInterfaceID);
+mDNSlocal mDNSBool DomainNameIsSingleLabel(const domainname *inName);
+mDNSlocal mDNSBool StringEndsWithDot(const char *inString);
+mDNSlocal const domainname * NextSearchDomain(QueryRecordOp *inOp);
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
+mDNSlocal mDNSBool DomainNameIsInSearchList(const domainname *domain, mDNSBool inExcludeLocal);
+#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
+mDNSlocal void NotifyWebContentFilter(const ResourceRecord *inAnswer, uid_t inUID);
+#endif
+
+mDNSexport void GetAddrInfoClientRequestParamsInit(GetAddrInfoClientRequestParams *inParams)
+{
+ mDNSPlatformMemZero(inParams, (mDNSu32)sizeof(*inParams));
+}
+
+mDNSexport mStatus GetAddrInfoClientRequestStart(GetAddrInfoClientRequest *inRequest,
+ const GetAddrInfoClientRequestParams *inParams, QueryRecordResultHandler inResultHandler, void *inResultContext)
+{
+ mStatus err;
+ domainname hostname;
+ mDNSBool appendSearchDomains;
+ mDNSInterfaceID interfaceID;
+ DNSServiceFlags flags;
+ mDNSs32 serviceID;
+ QueryRecordOpParams opParams;
+
+ if (!MakeDomainNameFromDNSNameString(&hostname, inParams->hostnameStr))
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%u] ERROR: bad hostname '" PRI_S "'", inParams->requestID, inParams->hostnameStr);
+ err = mStatus_BadParamErr;
+ goto exit;
+ }
+
+ if (inParams->protocols & ~(kDNSServiceProtocol_IPv4|kDNSServiceProtocol_IPv6))
+ {
+ err = mStatus_BadParamErr;
+ goto exit;
+ }
+
+ flags = inParams->flags;
+ if (inParams->protocols == 0)
+ {
+ flags |= kDNSServiceFlagsSuppressUnusable;
+ inRequest->protocols = kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6;
+ }
+ else
+ {
+ inRequest->protocols = inParams->protocols;
+ }
+
+ if (flags & kDNSServiceFlagsServiceIndex)
+ {
+ // NOTE: kDNSServiceFlagsServiceIndex flag can only be set for DNSServiceGetAddrInfo()
+ LogInfo("GetAddrInfoClientRequestStart: kDNSServiceFlagsServiceIndex is SET by the client");
+
+ // If kDNSServiceFlagsServiceIndex is SET, interpret the interfaceID as the serviceId and set the interfaceID to 0.
+ serviceID = (mDNSs32)inParams->interfaceIndex;
+ interfaceID = mDNSNULL;
+ }
+ else
+ {
+ serviceID = -1;
+ err = InterfaceIndexToInterfaceID(inParams->interfaceIndex, &interfaceID);
+ if (err) goto exit;
+ }
+ inRequest->interfaceID = interfaceID;
+
+ if (!StringEndsWithDot(inParams->hostnameStr) && (AlwaysAppendSearchDomains || DomainNameIsSingleLabel(&hostname)))
+ {
+ appendSearchDomains = mDNStrue;
+ }
+ else
+ {
+ appendSearchDomains = mDNSfalse;
+ }
+ QueryRecordOpParamsInit(&opParams);
+ opParams.requestID = inParams->requestID;
+ opParams.qname = &hostname;
+ opParams.qclass = kDNSClass_IN;
+ opParams.interfaceID = inRequest->interfaceID;
+ opParams.serviceID = serviceID;
+ opParams.flags = flags;
+ opParams.appendSearchDomains = appendSearchDomains;
+ opParams.effectivePID = inParams->effectivePID;
+ opParams.effectiveUUID = inParams->effectiveUUID;
+ opParams.peerUID = inParams->peerUID;
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ opParams.resolverUUID = inParams->resolverUUID;
+ opParams.customID = inParams->customID;
+ opParams.needEncryption = inParams->needEncryption;
+#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
+ opParams.peerAuditToken = inParams->peerAuditToken;
+ opParams.delegatorAuditToken = inParams->delegatorAuditToken;
+ opParams.isInAppBrowserRequest = inParams->isInAppBrowserRequest;
+#endif
+ if (inRequest->protocols & kDNSServiceProtocol_IPv6)
+ {
+ err = QueryRecordOpCreate(&inRequest->op6);
+ if (err) goto exit;
+
+ opParams.qtype = kDNSType_AAAA;
+ err = QueryRecordOpStart(inRequest->op6, &opParams, inResultHandler, inResultContext);
+ if (err) goto exit;
+ }
+ if (inRequest->protocols & kDNSServiceProtocol_IPv4)
+ {
+ err = QueryRecordOpCreate(&inRequest->op4);
+ if (err) goto exit;
+
+ opParams.qtype = kDNSType_A;
+ err = QueryRecordOpStart(inRequest->op4, &opParams, inResultHandler, inResultContext);
+ if (err) goto exit;
+ }
+ err = mStatus_NoError;
+
+exit:
+ if (err) GetAddrInfoClientRequestStop(inRequest);
+ return err;
+}
+
+mDNSexport void GetAddrInfoClientRequestStop(GetAddrInfoClientRequest *inRequest)
+{
+ if (inRequest->op4) QueryRecordOpStop(inRequest->op4);
+ if (inRequest->op6) QueryRecordOpStop(inRequest->op6);
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
+ {
+ const QueryRecordOp * const op4 = inRequest->op4;
+ const QueryRecordOp * const op6 = inRequest->op6;
+ const DNSQuestion * q4 = mDNSNULL;
+ const DNSQuestion * q6 = mDNSNULL;
+
+ if (op4)
+ {
+ if (op4->answered)
+ {
+ // If we have a v4 answer and if we timed out prematurely before, provide a trigger to the upper layer so
+ // that it can retry questions if needed. - Mohan
+ q4 = &op4->q;
+ }
+ else if (op4->q.TimeoutQuestion)
+ {
+ // If we are not delivering answers, we may be timing out prematurely. Note down the current state so that
+ // we know to retry when we see a valid response again. - Mohan
+ mDNSPlatformUpdateDNSStatus(&op4->q);
+ }
+ }
+ if (op6)
+ {
+ if (op6->answered)
+ {
+ q6 = &op6->q;
+ }
+ else if (op6->q.TimeoutQuestion)
+ {
+ mDNSPlatformUpdateDNSStatus(&op6->q);
+ }
+ }
+ mDNSPlatformTriggerDNSRetry(q4, q6);
+ }
+#endif
+
+ if (inRequest->op4)
+ {
+ QueryRecordOpFree(inRequest->op4);
+ inRequest->op4 = mDNSNULL;
+ }
+ if (inRequest->op6)
+ {
+ QueryRecordOpFree(inRequest->op6);
+ inRequest->op6 = mDNSNULL;
+ }
+}
+
+mDNSexport const domainname * GetAddrInfoClientRequestGetQName(const GetAddrInfoClientRequest *inRequest)
+{
+ if (inRequest->op4) return &inRequest->op4->q.qname;
+ if (inRequest->op6) return &inRequest->op6->q.qname;
+ return (const domainname *)"";
+}
+
+mDNSexport mDNSBool GetAddrInfoClientRequestIsMulticast(const GetAddrInfoClientRequest *inRequest)
+{
+ if ((inRequest->op4 && QueryRecordOpIsMulticast(inRequest->op4)) ||
+ (inRequest->op6 && QueryRecordOpIsMulticast(inRequest->op6)))
+ {
+ return mDNStrue;
+ }
+ return mDNSfalse;
+}
+
+mDNSexport void QueryRecordClientRequestParamsInit(QueryRecordClientRequestParams *inParams)
+{
+ mDNSPlatformMemZero(inParams, (mDNSu32)sizeof(*inParams));
+}
+
+mDNSexport mStatus QueryRecordClientRequestStart(QueryRecordClientRequest *inRequest,
+ const QueryRecordClientRequestParams *inParams, QueryRecordResultHandler inResultHandler, void *inResultContext)
+{
+ mStatus err;
+ domainname qname;
+ mDNSInterfaceID interfaceID;
+ mDNSBool appendSearchDomains;
+ QueryRecordOpParams opParams;
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+ dnssec_context_t * dnssecContext = mDNSNULL;
+#endif
+
+ err = InterfaceIndexToInterfaceID(inParams->interfaceIndex, &interfaceID);
+ if (err) goto exit;
+
+ if (!MakeDomainNameFromDNSNameString(&qname, inParams->qnameStr))
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%u] ERROR: bad domain name '" PRI_S "'", inParams->requestID, inParams->qnameStr);
+ err = mStatus_BadParamErr;
+ goto exit;
+ }
+
+ if (RecordTypeIsAddress(inParams->qtype) && !StringEndsWithDot(inParams->qnameStr) &&
+ (AlwaysAppendSearchDomains || DomainNameIsSingleLabel(&qname)))
+ {
+ appendSearchDomains = mDNStrue;
+ }
+ else
+ {
+ appendSearchDomains = mDNSfalse;
+ }
+ QueryRecordOpParamsInit(&opParams);
+ opParams.requestID = inParams->requestID;
+ opParams.qname = &qname;
+ opParams.qtype = inParams->qtype;
+ opParams.qclass = inParams->qclass;
+ opParams.interfaceID = interfaceID;
+ opParams.appendSearchDomains = appendSearchDomains;
+ opParams.effectivePID = inParams->effectivePID;
+ opParams.effectiveUUID = inParams->effectiveUUID;
+ opParams.peerUID = inParams->peerUID;
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ opParams.resolverUUID = inParams->resolverUUID;
+ opParams.customID = inParams->customID;
+ opParams.needEncryption = inParams->needEncryption;
+#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
+ opParams.peerAuditToken = inParams->peerAuditToken;
+ opParams.delegatorAuditToken = inParams->delegatorAuditToken;
+ opParams.isInAppBrowserRequest = inParams->isInAppBrowserRequest;
+#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+ // Query ends with ".local." and query for RRSIG or ANY type cannot be validated by DNSSEC even if the user sets the
+ // kDNSServiceFlagsEnableDNSSEC flag.
+ if (FLAGS_CONTAIN_DNSOK_BIT(inParams->flags) && is_eligible_for_dnssec(&qname, inParams->qtype))
+ {
+ opParams.flags = inParams->flags | kDNSServiceFlagsReturnIntermediates; // to handle CNAME reference
+ err = create_dnssec_context_t(inRequest, inParams->requestID, &qname, inParams->qtype, inParams->qclass,
+ interfaceID, -1, inParams->flags, appendSearchDomains, inParams->effectivePID, inParams->effectiveUUID,
+ inParams->peerUID,
+#if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
+ inParams->peerAuditToken, inParams->delegatorAuditToken,
+#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ mDNSNULL, inParams->needEncryption, inParams->customID,
+#endif
+ inResultHandler, inResultContext, mDNSNULL, &dnssecContext);
+ require_action(err == mStatus_NoError, exit, log_debug("create_dnssec_context_t failed; error_description='%s'",
+ mStatusDescription(err)));
+
+ err = QueryRecordOpStart(&inRequest->op, &opParams, query_record_result_reply_with_dnssec, dnssecContext);
+ } else
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+ {
+ opParams.flags = inParams->flags;
+ err = QueryRecordOpStart(&inRequest->op, &opParams, inResultHandler, inResultContext);
+ }
+
+exit:
+ if (err) QueryRecordClientRequestStop(inRequest);
+ return err;
+}
+
+mDNSexport void QueryRecordClientRequestStop(QueryRecordClientRequest *inRequest)
+{
+ QueryRecordOpStop(&inRequest->op);
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+ stop_dnssec_if_enable_dnssec(inRequest);
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
+ if (inRequest->op.answered)
+ {
+ DNSQuestion *v4q, *v6q;
+ // If we are receiving positive answers, provide the hint to the upper layer. - Mohan
+ v4q = (inRequest->op.q.qtype == kDNSType_A) ? &inRequest->op.q : mDNSNULL;
+ v6q = (inRequest->op.q.qtype == kDNSType_AAAA) ? &inRequest->op.q : mDNSNULL;
+ mDNSPlatformTriggerDNSRetry(v4q, v6q);
+ }
+#endif
+}
+
+mDNSexport const domainname * QueryRecordClientRequestGetQName(const QueryRecordClientRequest *inRequest)
+{
+ return &inRequest->op.q.qname;
+}
+
+mDNSexport mDNSu16 QueryRecordClientRequestGetType(const QueryRecordClientRequest *inRequest)
+{
+ return inRequest->op.q.qtype;
+}
+
+mDNSexport mDNSBool QueryRecordClientRequestIsMulticast(QueryRecordClientRequest *inRequest)
+{
+ return (QueryRecordOpIsMulticast(&inRequest->op) ? mDNStrue : mDNSfalse);
+}
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+mDNSexport mStatus QueryRecordOpStartForClientRequest(
+ QueryRecordOp * inOp,
+ mDNSu32 inReqID,
+ const domainname * inQName,
+ mDNSu16 inQType,
+ mDNSu16 inQClass,
+ mDNSInterfaceID inInterfaceID,
+ mDNSs32 inServiceID,
+ mDNSu32 inFlags,
+ mDNSBool inAppendSearchDomains,
+ mDNSs32 inPID,
+ const mDNSu8 inUUID[UUID_SIZE],
+ mDNSu32 inUID,
+#if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
+ const audit_token_t * inPeerAuditTokenPtr,
+ const audit_token_t * inDelegateAuditTokenPtr,
+#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ const mDNSu8 inResolverUUID[UUID_SIZE],
+ mDNSBool inNeedEncryption,
+ const mdns_dns_service_id_t inCustomID,
+#endif
+ QueryRecordResultHandler inResultHandler,
+ void * inResultContext) {
+ QueryRecordOpParams opParams;
+ QueryRecordOpParamsInit(&opParams);
+ opParams.requestID = inReqID;
+ opParams.qname = inQName;
+ opParams.qtype = inQType;
+ opParams.qclass = inQClass;
+ opParams.interfaceID = inInterfaceID;
+ opParams.serviceID = inServiceID;
+ opParams.flags = inFlags;
+ opParams.appendSearchDomains = inAppendSearchDomains;
+ opParams.effectivePID = inPID;
+ opParams.effectiveUUID = inUUID;
+ opParams.peerUID = inUID;
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ opParams.resolverUUID = inResolverUUID;
+ opParams.customID = inCustomID;
+ opParams.needEncryption = inNeedEncryption;
+#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
+ opParams.peerAuditToken = inPeerAuditTokenPtr;
+ opParams.delegatorAuditToken = inDelegateAuditTokenPtr;
+#endif
+ return QueryRecordOpStart(inOp, &opParams, inResultHandler, inResultContext);
+}
+
+mDNSexport void QueryRecordOpStopForClientRequest(QueryRecordOp *op) {
+ QueryRecordOpStop(op);
+}
+
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+
+mDNSlocal mStatus QueryRecordOpCreate(QueryRecordOp **outOp)
+{
+ mStatus err;
+ QueryRecordOp *op;
+
+ op = (QueryRecordOp *) mDNSPlatformMemAllocateClear(sizeof(*op));
+ if (!op)
+ {
+ err = mStatus_NoMemoryErr;
+ goto exit;
+ }
+ *outOp = op;
+ err = mStatus_NoError;
+
+exit:
+ return err;
+}
+
+mDNSlocal void QueryRecordOpFree(QueryRecordOp *operation)
+{
+ mDNSPlatformMemFree(operation);
+}
+
+#define VALID_MSAD_SRV_TRANSPORT(T) \
+ (SameDomainLabel((T)->c, (const mDNSu8 *)"\x4_tcp") || SameDomainLabel((T)->c, (const mDNSu8 *)"\x4_udp"))
+#define VALID_MSAD_SRV(Q) ((Q)->qtype == kDNSType_SRV && VALID_MSAD_SRV_TRANSPORT(SecondLabel(&(Q)->qname)))
+
+mDNSlocal mStatus QueryRecordOpStart(QueryRecordOp *inOp, const QueryRecordOpParams *inParams,
+ QueryRecordResultHandler inResultHandler, void *inResultContext)
+{
+ mStatus err;
+ DNSQuestion * const q = &inOp->q;
+ mDNSu32 len;
+
+ // Save the original qname.
+
+ len = DomainNameLength(inParams->qname);
+ inOp->qname = (domainname *) mDNSPlatformMemAllocate(len);
+ if (!inOp->qname)
+ {
+ err = mStatus_NoMemoryErr;
+ goto exit;
+ }
+ mDNSPlatformMemCopy(inOp->qname, inParams->qname, len);
+
+ inOp->interfaceID = inParams->interfaceID;
+ inOp->reqID = inParams->requestID;
+ inOp->resultHandler = inResultHandler;
+ inOp->resultContext = inResultContext;
+
+ // Set up DNSQuestion.
+
+ if (EnableAllowExpired && (inParams->flags & kDNSServiceFlagsAllowExpiredAnswers))
+ {
+ q->allowExpired = AllowExpired_AllowExpiredAnswers;
+ }
+ else
+ {
+ q->allowExpired = AllowExpired_None;
+ }
+ q->ServiceID = inParams->serviceID;
+#if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
+ q->inAppBrowserRequest = inParams->isInAppBrowserRequest;
+ if (inParams->peerAuditToken)
+ {
+ q->peerAuditToken = *inParams->peerAuditToken;
+ }
+ if (inParams->delegatorAuditToken)
+ {
+ q->delegateAuditToken = *inParams->delegatorAuditToken;
+ }
+#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ if (inParams->resolverUUID)
+ {
+ mDNSPlatformMemCopy(q->ResolverUUID, inParams->resolverUUID, UUID_SIZE);
+ }
+#endif
+ q->InterfaceID = inParams->interfaceID;
+ q->flags = inParams->flags;
+ AssignDomainName(&q->qname, inParams->qname);
+ q->qtype = inParams->qtype;
+ q->qclass = inParams->qclass;
+ q->LongLived = (inParams->flags & kDNSServiceFlagsLongLivedQuery) ? mDNStrue : mDNSfalse;
+ q->ForceMCast = (inParams->flags & kDNSServiceFlagsForceMulticast) ? mDNStrue : mDNSfalse;
+ q->ReturnIntermed = (inParams->flags & kDNSServiceFlagsReturnIntermediates) ? mDNStrue : mDNSfalse;
+ q->SuppressUnusable = (inParams->flags & kDNSServiceFlagsSuppressUnusable) ? mDNStrue : mDNSfalse;
+ q->TimeoutQuestion = (inParams->flags & kDNSServiceFlagsTimeout) ? mDNStrue : mDNSfalse;
+ q->UseBackgroundTraffic = (inParams->flags & kDNSServiceFlagsBackgroundTrafficClass) ? mDNStrue : mDNSfalse;
+ q->AppendSearchDomains = inParams->appendSearchDomains;
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ q->RequireEncryption = inParams->needEncryption;
+ q->CustomID = inParams->customID;
+#endif
+ q->InitialCacheMiss = mDNSfalse;
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+ err = initialize_dnssec_status_t(&q->DNSSECStatus, inParams->qname, inParams->qtype, inParams->flags, inResultContext);
+ require_action(err == mStatus_NoError, exit, log_debug("initialize_dnssec_status failed; error_description='%s'", mStatusDescription(err)));
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+
+ q->pid = inParams->effectivePID;
+ if (inParams->effectiveUUID)
+ {
+ mDNSPlatformMemCopy(q->uuid, inParams->effectiveUUID, UUID_SIZE);
+ }
+ q->euid = inParams->peerUID;
+ q->request_id = inParams->requestID;
+ q->QuestionCallback = QueryRecordOpCallback;
+ q->ResetHandler = QueryRecordOpResetHandler;
+
+ // For single label queries that are not fully qualified, look at /etc/hosts, cache and try search domains before trying
+ // them on the wire as a single label query. - Mohan
+
+ if (q->AppendSearchDomains && DomainNameIsSingleLabel(inOp->qname)) q->InterfaceID = mDNSInterface_LocalOnly;
+ err = QueryRecordOpStartQuestion(inOp, q);
+ if (err) goto exit;
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+ if (callExternalHelpers(q->InterfaceID, &q->qname, q->flags))
+ {
+ external_start_browsing_for_service(q->InterfaceID, &q->qname, q->qtype, q->flags, q->pid);
+ }
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
+ if ((RecordTypeIsAddress(q->qtype) || VALID_MSAD_SRV(&inOp->q)) && !q->ForceMCast &&
+ SameDomainLabel(LastLabel(&q->qname), (const mDNSu8 *)&localdomain))
+ {
+ DNSQuestion * q2;
+
+ q2 = (DNSQuestion *) mDNSPlatformMemAllocate((mDNSu32)sizeof(*inOp->q2));
+ if (!q2)
+ {
+ err = mStatus_NoMemoryErr;
+ goto exit;
+ }
+ inOp->q2 = q2;
+
+ *q2 = *q;
+ q2->IsUnicastDotLocal = mDNStrue;
+
+ if ((CountLabels(&q2->qname) == 2) && !SameDomainName(&q2->qname, &ActiveDirectoryPrimaryDomain)
+ && !DomainNameIsInSearchList(&q2->qname, mDNSfalse))
+ {
+ inOp->q2Type = q2->qtype;
+ inOp->q2LongLived = q2->LongLived;
+ inOp->q2ReturnIntermed = q2->ReturnIntermed;
+ inOp->q2TimeoutQuestion = q2->TimeoutQuestion;
+ inOp->q2AppendSearchDomains = q2->AppendSearchDomains;
+
+ AssignDomainName(&q2->qname, &localdomain);
+ q2->qtype = kDNSType_SOA;
+ q2->LongLived = mDNSfalse;
+ q2->ReturnIntermed = mDNStrue;
+ q2->TimeoutQuestion = mDNSfalse;
+ q2->AppendSearchDomains = mDNSfalse;
+ }
+
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u] QueryRecordOpStart: starting parallel unicast query for " PRI_DM_NAME " " PUB_S,
+ inOp->reqID, DM_NAME_PARAM(&q2->qname), DNSTypeName(q2->qtype));
+
+ err = QueryRecordOpStartQuestion(inOp, q2);
+ if (err) goto exit;
+ }
+#endif
+ err = mStatus_NoError;
+
+exit:
+ if (err) QueryRecordOpStop(inOp);
+ return err;
+}
+
+mDNSlocal void QueryRecordOpStop(QueryRecordOp *op)
+{
+ if (op->q.QuestionContext)
+ {
+ QueryRecordOpStopQuestion(&op->q);
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+ if (callExternalHelpers(op->q.InterfaceID, op->qname, op->q.flags))
+ {
+ external_stop_browsing_for_service(op->q.InterfaceID, &op->q.qname, op->q.qtype, op->q.flags, op->q.pid);
+ }
+#endif
+ }
+ if (op->qname)
+ {
+ mDNSPlatformMemFree(op->qname);
+ op->qname = mDNSNULL;
+ }
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
+ if (op->q2)
+ {
+ if (op->q2->QuestionContext) QueryRecordOpStopQuestion(op->q2);
+ mDNSPlatformMemFree(op->q2);
+ op->q2 = mDNSNULL;
+ }
+#endif
+}
+
+mDNSlocal mDNSBool QueryRecordOpIsMulticast(const QueryRecordOp *op)
+{
+ return ((mDNSOpaque16IsZero(op->q.TargetQID) && (op->q.ThisQInterval > 0)) ? mDNStrue : mDNSfalse);
+}
+
+// GetTimeNow is a callback-safe alternative to mDNS_TimeNow(), which expects to be called with m->mDNS_busy == 0.
+mDNSlocal mDNSs32 GetTimeNow(mDNS *m)
+{
+ mDNSs32 time;
+ mDNS_Lock(m);
+ time = m->timenow;
+ mDNS_Unlock(m);
+ return time;
+}
+
+mDNSlocal void QueryRecordOpCallback(mDNS *m, DNSQuestion *inQuestion, const ResourceRecord *inAnswer, QC_result inAddRecord)
+{
+ mStatus resultErr;
+ QueryRecordOp *const op = (QueryRecordOp *)inQuestion->QuestionContext;
+ const domainname * domain;
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
+ if ((inQuestion == op->q2) && (inQuestion->qtype == kDNSType_SOA))
+ {
+ DNSQuestion * const q2 = op->q2;
+
+ if (inAnswer->rrtype != kDNSType_SOA) goto exit;
+ QueryRecordOpStopQuestion(q2);
+
+ // Restore DNSQuestion variables that were modified for the SOA query.
+
+ q2->qtype = op->q2Type;
+ q2->LongLived = op->q2LongLived;
+ q2->ReturnIntermed = op->q2ReturnIntermed;
+ q2->TimeoutQuestion = op->q2TimeoutQuestion;
+ q2->AppendSearchDomains = op->q2AppendSearchDomains;
+
+ if (inAnswer->RecordType != kDNSRecordTypePacketNegative)
+ {
+ QueryRecordOpRestartUnicastQuestion(op, q2, mDNSNULL);
+ }
+ else if (q2->AppendSearchDomains)
+ {
+ domain = NextSearchDomain(op);
+ if (domain) QueryRecordOpRestartUnicastQuestion(op, q2, domain);
+ }
+ goto exit;
+ }
+#endif
+
+ if (inAddRecord == QC_suppressed)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+ "[R%u] QueryRecordOpCallback: Suppressed question " PRI_DM_NAME " (" PUB_S ")",
+ op->reqID, DM_NAME_PARAM(&inQuestion->qname), DNSTypeName(inQuestion->qtype));
+
+ resultErr = kDNSServiceErr_NoSuchRecord;
+ }
+ else if (inAnswer->RecordType == kDNSRecordTypePacketNegative)
+ {
+ if (inQuestion->TimeoutQuestion && ((GetTimeNow(m) - inQuestion->StopTime) >= 0))
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u] QueryRecordOpCallback: Question " PRI_DM_NAME " (" PUB_S ") timing out, InterfaceID %p",
+ op->reqID, DM_NAME_PARAM(&inQuestion->qname), DNSTypeName(inQuestion->qtype),
+ inQuestion->InterfaceID);
+ resultErr = kDNSServiceErr_Timeout;
+ }
+ else
+ {
+ if (inQuestion->AppendSearchDomains && (op->searchListIndex >= 0) && inAddRecord)
+ {
+ domain = NextSearchDomain(op);
+ if (domain || DomainNameIsSingleLabel(op->qname))
+ {
+ QueryRecordOpStopQuestion(inQuestion);
+ QueryRecordOpRestartUnicastQuestion(op, inQuestion, domain);
+ goto exit;
+ }
+ }
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
+ if (!inAnswer->InterfaceID && IsLocalDomain(inAnswer->name))
+ {
+ if ((RecordTypeIsAddress(inQuestion->qtype) &&
+ (inAnswer->negativeRecordType == kNegativeRecordType_NoData)) ||
+ DomainNameIsInSearchList(&inQuestion->qname, mDNStrue))
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u] QueryRecordOpCallback: Question " PRI_DM_NAME " (" PUB_S ") answering local with negative unicast response",
+ op->reqID, DM_NAME_PARAM(&inQuestion->qname), DNSTypeName(inQuestion->qtype));
+ }
+ else
+ {
+ goto exit;
+ }
+ }
+#endif
+ resultErr = kDNSServiceErr_NoSuchRecord;
+ }
+ }
+ else
+ {
+ resultErr = kDNSServiceErr_NoError;
+ }
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
+ if ((resultErr != kDNSServiceErr_Timeout) && (inAddRecord == QC_add))
+ {
+ op->answered = mDNStrue;
+ }
+#endif
+
+ if (op->resultHandler) op->resultHandler(m, inQuestion, inAnswer, inAddRecord, resultErr, op->resultContext);
+ if (resultErr == kDNSServiceErr_Timeout) QueryRecordOpStopQuestion(inQuestion);
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
+ NotifyWebContentFilter(inAnswer, inQuestion->euid);
+#endif
+
+exit:
+ return;
+}
+
+mDNSlocal void QueryRecordOpResetHandler(DNSQuestion *inQuestion)
+{
+ QueryRecordOp *const op = (QueryRecordOp *)inQuestion->QuestionContext;
+
+ AssignDomainName(&inQuestion->qname, op->qname);
+ if (inQuestion->AppendSearchDomains && DomainNameIsSingleLabel(op->qname))
+ {
+ inQuestion->InterfaceID = mDNSInterface_LocalOnly;
+ }
+ else
+ {
+ inQuestion->InterfaceID = op->interfaceID;
+ }
+ op->searchListIndex = 0;
+}
+
+mDNSlocal mStatus QueryRecordOpStartQuestion(QueryRecordOp *inOp, DNSQuestion *inQuestion)
+{
+ mStatus err;
+
+ inQuestion->QuestionContext = inOp;
+ err = mDNS_StartQuery(&mDNSStorage, inQuestion);
+ if (err)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%u] ERROR: QueryRecordOpStartQuestion mDNS_StartQuery for " PRI_DM_NAME " " PUB_S " failed with error %d",
+ inOp->reqID, DM_NAME_PARAM(&inQuestion->qname), DNSTypeName(inQuestion->qtype), err);
+ inQuestion->QuestionContext = mDNSNULL;
+ }
+ return err;
+}
+
+mDNSlocal mStatus QueryRecordOpStopQuestion(DNSQuestion *inQuestion)
+{
+ mStatus err;
+
+ err = mDNS_StopQuery(&mDNSStorage, inQuestion);
+ inQuestion->QuestionContext = mDNSNULL;
+ return err;
+}
+
+mDNSlocal mStatus QueryRecordOpRestartUnicastQuestion(QueryRecordOp *inOp, DNSQuestion *inQuestion,
+ const domainname *inSearchDomain)
+{
+ mStatus err;
+
+ inQuestion->InterfaceID = inOp->interfaceID;
+ AssignDomainName(&inQuestion->qname, inOp->qname);
+ if (inSearchDomain) AppendDomainName(&inQuestion->qname, inSearchDomain);
+ if (SameDomainLabel(LastLabel(&inQuestion->qname), (const mDNSu8 *)&localdomain))
+ {
+ inQuestion->IsUnicastDotLocal = mDNStrue;
+ }
+ else
+ {
+ inQuestion->IsUnicastDotLocal = mDNSfalse;
+ }
+ err = QueryRecordOpStartQuestion(inOp, inQuestion);
+ return err;
+}
+
+mDNSlocal mStatus InterfaceIndexToInterfaceID(mDNSu32 inInterfaceIndex, mDNSInterfaceID *outInterfaceID)
+{
+ mStatus err;
+ mDNSInterfaceID interfaceID;
+
+ interfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, inInterfaceIndex);
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNREADY_INTERFACES)
+ // The request is scoped to a specific interface index, but the interface is not currently in our list.
+ if ((inInterfaceIndex != kDNSServiceInterfaceIndexAny) && (interfaceID == mDNSInterface_Any))
+ {
+ static dispatch_once_t getLoopbackIndexOnce = 0;
+ static mDNSu32 loopbackIndex = 0;
+
+ dispatch_once(&getLoopbackIndexOnce,
+ ^{
+ loopbackIndex = if_nametoindex("lo0");
+ });
+
+ // If it's one of the specially defined inteface index values, just return an error. Also, caller should return an
+ // error immediately if lo0 is not configured into the current active interfaces. See <rdar://problem/21967160>.
+ if ((inInterfaceIndex == kDNSServiceInterfaceIndexLocalOnly) ||
+ (inInterfaceIndex == kDNSServiceInterfaceIndexUnicast) ||
+ (inInterfaceIndex == kDNSServiceInterfaceIndexP2P) ||
+ (inInterfaceIndex == kDNSServiceInterfaceIndexBLE) ||
+ (inInterfaceIndex == loopbackIndex))
+ {
+ LogInfo("ERROR: bad interfaceIndex %d", inInterfaceIndex);
+ err = mStatus_BadParamErr;
+ goto exit;
+ }
+
+ // Otherwise, use the specified interface index value and the request will be applied to that interface when it
+ // comes up.
+ interfaceID = (mDNSInterfaceID)(uintptr_t)inInterfaceIndex;
+ LogInfo("Query pending for interface index %d", inInterfaceIndex);
+ }
+#endif
+
+ *outInterfaceID = interfaceID;
+ err = mStatus_NoError;
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNREADY_INTERFACES)
+exit:
+#endif
+ return err;
+}
+
+mDNSlocal mDNSBool DomainNameIsSingleLabel(const domainname *inName)
+{
+ const mDNSu8 *const label = inName->c;
+ return (((label[0] != 0) && (label[1 + label[0]] == 0)) ? mDNStrue : mDNSfalse);
+}
+
+mDNSlocal mDNSBool StringEndsWithDot(const char *inString)
+{
+ const char * ptr;
+ mDNSu32 escapeCount;
+ mDNSBool result;
+
+ // Loop invariant: escapeCount is the number of consecutive escape characters that immediately precede *ptr.
+ // - If escapeCount is even, then *ptr is immediately preceded by escapeCount / 2 consecutive literal backslash
+ // characters, so *ptr is not escaped.
+ // - If escapeCount is odd, then *ptr is immediately preceded by (escapeCount - 1) / 2 consecutive literal backslash
+ // characters followed by an escape character, so *ptr is escaped.
+ escapeCount = 0;
+ result = mDNSfalse;
+ for (ptr = inString; *ptr != '\0'; ptr++)
+ {
+ if (*ptr == '\\')
+ {
+ escapeCount++;
+ }
+ else
+ {
+ if ((*ptr == '.') && (ptr[1] == '\0'))
+ {
+ if ((escapeCount % 2) == 0) result = mDNStrue;
+ break;
+ }
+ escapeCount = 0;
+ }
+ }
+ return result;
+}
+
+mDNSlocal const domainname * NextSearchDomain(QueryRecordOp *inOp)
+{
+ const domainname * domain;
+
+ while ((domain = uDNS_GetNextSearchDomain(inOp->interfaceID, &inOp->searchListIndex, mDNSfalse)) != mDNSNULL)
+ {
+ if ((DomainNameLength(inOp->qname) - 1 + DomainNameLength(domain)) <= MAX_DOMAIN_NAME) break;
+ }
+ if (!domain) inOp->searchListIndex = -1;
+ return domain;
+}
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
+mDNSlocal mDNSBool DomainNameIsInSearchList(const domainname *inName, mDNSBool inExcludeLocal)
+{
+ const SearchListElem * item;
+ int labelCount, domainLabelCount;
+
+ labelCount = CountLabels(inName);
+ for (item = SearchList; item; item = item->next)
+ {
+ if (inExcludeLocal && SameDomainName(&item->domain, &localdomain)) continue;
+ domainLabelCount = CountLabels(&item->domain);
+ if (labelCount >= domainLabelCount)
+ {
+ if (SameDomainName(&item->domain, SkipLeadingLabels(inName, (labelCount - domainLabelCount))))
+ {
+ return mDNStrue;
+ }
+ }
+ }
+ return mDNSfalse;
+}
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
+mDNSlocal void NotifyWebContentFilter(const ResourceRecord *inAnswer, uid_t inUID)
+{
+ if (WCFIsServerRunning)
+ {
+ const mDNS *const m = &mDNSStorage;
+
+ if (WCFIsServerRunning(m->WCF) && inAnswer->rdlength != 0)
+ {
+ struct sockaddr_storage addr;
+ addr.ss_len = 0;
+ if (inAnswer->rrtype == kDNSType_A || inAnswer->rrtype == kDNSType_AAAA)
+ {
+ if (inAnswer->rrtype == kDNSType_A)
+ {
+ struct sockaddr_in *const sin = (struct sockaddr_in *)&addr;
+ sin->sin_port = 0;
+ // Instead of this stupid call to putRData it would be much simpler to just assign the value in the sensible way, like this:
+ // sin->sin_addr.s_addr = inAnswer->rdata->u.ipv4.NotAnInteger;
+ if (!putRData(mDNSNULL, (mDNSu8 *)&sin->sin_addr, (mDNSu8 *)(&sin->sin_addr + sizeof(mDNSv4Addr)), inAnswer))
+ LogMsg("NotifyWebContentFilter: WCF AF_INET putRData failed");
+ else
+ {
+ addr.ss_len = sizeof (struct sockaddr_in);
+ addr.ss_family = AF_INET;
+ }
+ }
+ else if (inAnswer->rrtype == kDNSType_AAAA)
+ {
+ struct sockaddr_in6 *const sin6 = (struct sockaddr_in6 *)&addr;
+ sin6->sin6_port = 0;
+ // Instead of this stupid call to putRData it would be much simpler to just assign the value in the sensible way, like this:
+ // sin6->sin6_addr.__u6_addr.__u6_addr32[0] = inAnswer->rdata->u.ipv6.l[0];
+ // sin6->sin6_addr.__u6_addr.__u6_addr32[1] = inAnswer->rdata->u.ipv6.l[1];
+ // sin6->sin6_addr.__u6_addr.__u6_addr32[2] = inAnswer->rdata->u.ipv6.l[2];
+ // sin6->sin6_addr.__u6_addr.__u6_addr32[3] = inAnswer->rdata->u.ipv6.l[3];
+ if (!putRData(mDNSNULL, (mDNSu8 *)&sin6->sin6_addr, (mDNSu8 *)(&sin6->sin6_addr + sizeof(mDNSv6Addr)), inAnswer))
+ LogMsg("NotifyWebContentFilter: WCF AF_INET6 putRData failed");
+ else
+ {
+ addr.ss_len = sizeof (struct sockaddr_in6);
+ addr.ss_family = AF_INET6;
+ }
+ }
+ if (addr.ss_len)
+ {
+ char name[MAX_ESCAPED_DOMAIN_NAME];
+ ConvertDomainNameToCString(inAnswer->name, name);
+
+ debugf("NotifyWebContentFilter: Name %s, uid %u, addr length %d", name, inUID, addr.ss_len);
+ if (WCFNameResolvesToAddr)
+ {
+ WCFNameResolvesToAddr(m->WCF, name, (struct sockaddr *)&addr, inUID);
+ }
+ }
+ }
+ else if (inAnswer->rrtype == kDNSType_CNAME)
+ {
+ domainname cname;
+ char name[MAX_ESCAPED_DOMAIN_NAME];
+ char cname_cstr[MAX_ESCAPED_DOMAIN_NAME];
+
+ if (!putRData(mDNSNULL, cname.c, (mDNSu8 *)(cname.c + MAX_DOMAIN_NAME), inAnswer))
+ LogMsg("NotifyWebContentFilter: WCF CNAME putRData failed");
+ else
+ {
+ ConvertDomainNameToCString(inAnswer->name, name);
+ ConvertDomainNameToCString(&cname, cname_cstr);
+ if (WCFNameResolvesToAddr)
+ {
+ WCFNameResolvesToName(m->WCF, name, cname_cstr, inUID);
+ }
+ }
+ }
+ }
+ }
+}
+#endif
diff --git a/usr/src/contrib/mDNSResponder/mDNSShared/ClientRequests.h b/usr/src/contrib/mDNSResponder/mDNSShared/ClientRequests.h
new file mode 100644
index 0000000000..c3a42f4337
--- /dev/null
+++ b/usr/src/contrib/mDNSResponder/mDNSShared/ClientRequests.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2018-2019 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ClientRequests_h
+#define __ClientRequests_h
+
+#include "mDNSEmbeddedAPI.h"
+#include "dns_sd_internal.h"
+
+typedef void (*QueryRecordResultHandler)(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord,
+ DNSServiceErrorType error, void *context);
+
+typedef struct
+{
+ DNSQuestion q; // DNSQuestion for record query.
+ domainname * qname; // Name of the original record.
+ mDNSInterfaceID interfaceID; // Interface over which to perform query.
+ QueryRecordResultHandler resultHandler; // Handler for query record operation results.
+ void * resultContext; // Context to pass to result handler.
+ mDNSu32 reqID; //
+ int searchListIndex; // Index that indicates the next search domain to try.
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
+ DNSQuestion * q2; // DNSQuestion for unicast version of a record with a dot-local name.
+ mDNSu16 q2Type; // q2's original qtype value.
+ mDNSBool q2LongLived; // q2's original LongLived value.
+ mDNSBool q2ReturnIntermed; // q2's original ReturnIntermed value.
+ mDNSBool q2TimeoutQuestion; // q2's original TimeoutQuestion value.
+ mDNSBool q2AppendSearchDomains; // q2's original AppendSearchDomains value.
+#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
+ mDNSBool answered; // True if the query was answered.
+#endif
+
+} QueryRecordOp;
+
+typedef struct
+{
+ mDNSInterfaceID interfaceID; // InterfaceID being used for query record operations.
+ mDNSu32 protocols; // Protocols (IPv4, IPv6) specified by client.
+ QueryRecordOp * op4; // Query record operation object for A record.
+ QueryRecordOp * op6; // Query record operation object for AAAA record.
+
+} GetAddrInfoClientRequest;
+
+typedef struct
+{
+ QueryRecordOp op; // Query record operation object.
+
+} QueryRecordClientRequest;
+
+typedef struct
+{
+ mDNSu32 requestID;
+ const char * hostnameStr;
+ mDNSu32 interfaceIndex;
+ DNSServiceFlags flags;
+ mDNSu32 protocols;
+ mDNSs32 effectivePID;
+ const mDNSu8 * effectiveUUID;
+ mDNSu32 peerUID;
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ mDNSBool needEncryption;
+ const mDNSu8 * resolverUUID;
+ mdns_dns_service_id_t customID;
+#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
+ const audit_token_t * peerAuditToken;
+ const audit_token_t * delegatorAuditToken;
+ mDNSBool isInAppBrowserRequest;
+#endif
+
+} GetAddrInfoClientRequestParams;
+
+typedef struct
+{
+ mDNSu32 requestID;
+ const char * qnameStr;
+ mDNSu32 interfaceIndex;
+ DNSServiceFlags flags;
+ mDNSu16 qtype;
+ mDNSu16 qclass;
+ mDNSs32 effectivePID;
+ const mDNSu8 * effectiveUUID;
+ mDNSu32 peerUID;
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ mDNSBool needEncryption;
+ const mDNSu8 * resolverUUID;
+ mdns_dns_service_id_t customID;
+#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
+ const audit_token_t * peerAuditToken;
+ const audit_token_t * delegatorAuditToken;
+ mDNSBool isInAppBrowserRequest;
+#endif
+
+} QueryRecordClientRequestParams;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+mDNSexport void GetAddrInfoClientRequestParamsInit(GetAddrInfoClientRequestParams *inParams);
+mDNSexport mStatus GetAddrInfoClientRequestStart(GetAddrInfoClientRequest *inRequest,
+ const GetAddrInfoClientRequestParams *inParams, QueryRecordResultHandler inResultHandler, void *inResultContext);
+mDNSexport void GetAddrInfoClientRequestStop(GetAddrInfoClientRequest *inRequest);
+mDNSexport const domainname * GetAddrInfoClientRequestGetQName(const GetAddrInfoClientRequest *inRequest);
+mDNSexport mDNSBool GetAddrInfoClientRequestIsMulticast(const GetAddrInfoClientRequest *inRequest);
+
+mDNSexport void QueryRecordClientRequestParamsInit(QueryRecordClientRequestParams *inParams);
+mDNSexport mStatus QueryRecordClientRequestStart(QueryRecordClientRequest *inRequest,
+ const QueryRecordClientRequestParams *inParams, QueryRecordResultHandler inResultHandler, void *inResultContext);
+mDNSexport void QueryRecordClientRequestStop(QueryRecordClientRequest *inRequest);
+mDNSexport const domainname * QueryRecordClientRequestGetQName(const QueryRecordClientRequest *inRequest);
+mDNSexport mDNSu16 QueryRecordClientRequestGetType(const QueryRecordClientRequest *inRequest);
+mDNSexport mDNSBool QueryRecordClientRequestIsMulticast(QueryRecordClientRequest *inRequest);
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+// This is a "mDNSexport" wrapper around the "static" QueryRecordOpStart that cannot be called by outside, which can be
+// called by the outside(dnssec related function).
+mDNSexport mStatus QueryRecordOpStartForClientRequest(
+ QueryRecordOp * inOp,
+ mDNSu32 inReqID,
+ const domainname * inQName,
+ mDNSu16 inQType,
+ mDNSu16 inQClass,
+ mDNSInterfaceID inInterfaceID,
+ mDNSs32 inServiceID,
+ mDNSu32 inFlags,
+ mDNSBool inAppendSearchDomains,
+ mDNSs32 inPID,
+ const mDNSu8 inUUID[UUID_SIZE],
+ mDNSu32 inUID,
+#if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
+ const audit_token_t * inPeerAuditTokenPtr,
+ const audit_token_t * inDelegateAuditTokenPtr,
+#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ const mDNSu8 inResolverUUID[UUID_SIZE],
+ mDNSBool inNeedEncryption,
+ const mdns_dns_service_id_t inCustomID,
+#endif
+ QueryRecordResultHandler inResultHandler,
+ void * inResultContext);
+
+mDNSexport void QueryRecordOpStopForClientRequest(QueryRecordOp *op);
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __ClientRequests_h
diff --git a/usr/src/contrib/mDNSResponder/mDNSShared/GenLinkedList.c b/usr/src/contrib/mDNSResponder/mDNSShared/GenLinkedList.c
index 1c6cb5be7c..2135c6ae88 100644
--- a/usr/src/contrib/mDNSResponder/mDNSShared/GenLinkedList.c
+++ b/usr/src/contrib/mDNSResponder/mDNSShared/GenLinkedList.c
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2011 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2003-2019 Apple Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -255,6 +254,9 @@ int OffsetRemoveFromList( GenLinkedOffsetList *pList, void *elem)
{
void *iElem, *lastElem;
+ if (elem == NULL) {
+ return 0;
+ }
for ( iElem = GetHeadPtr( pList), lastElem = NULL; iElem;
iElem = GetOffsetLink( pList, iElem))
{
diff --git a/usr/src/contrib/mDNSResponder/mDNSShared/PlatformCommon.c b/usr/src/contrib/mDNSResponder/mDNSShared/PlatformCommon.c
index 3a13d5ce53..5f785e8080 100644
--- a/usr/src/contrib/mDNSResponder/mDNSShared/PlatformCommon.c
+++ b/usr/src/contrib/mDNSResponder/mDNSShared/PlatformCommon.c
@@ -1,6 +1,6 @@
-/* -*- Mode: C; tab-width: 4 -*-
+/* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*-
*
- * Copyright (c) 2004-2015 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2019 Apple Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,15 +13,23 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
+ *
+ * This file defines functions that are common to platforms with Posix APIs.
+ * Current examples are mDNSMacOSX and mDNSPosix.
*/
#include <stdio.h> // Needed for fopen() etc.
#include <unistd.h> // Needed for close()
+#include <stdlib.h> // Needed for malloc()
#include <string.h> // Needed for strlen() etc.
#include <errno.h> // Needed for errno etc.
#include <sys/socket.h> // Needed for socket() etc.
#include <netinet/in.h> // Needed for sockaddr_in
#include <syslog.h>
+#include <sys/fcntl.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <assert.h>
#if APPLE_OSX_mDNSResponder
#include <os/log.h>
@@ -35,6 +43,126 @@
typedef unsigned int socklen_t;
#endif
+#if MDNS_MALLOC_DEBUGGING
+// We ONLY want this for malloc debugging--on a running production system we want to deal with
+// malloc failures, not just die. There is a small performance penalty for enabling these options
+// as well, so they are all only appropriate for debugging. The flags mean:
+//
+// A = warnings are errors
+// X = abort on failure
+// Z = sets J & R
+// J = allocated memory is initialized to a pattern
+// R causes realloc to always reallocate even if not needed
+
+char _malloc_options[] = "AXZ";
+
+mDNSlocal mDNSListValidator *listValidators;
+
+mDNSexport void mDNSPlatformAddListValidator(mDNSListValidator *lv, mDNSListValidationFunction *lvf,
+ const char *lvfName, void *context)
+{
+ mDNSPlatformMemZero(lv, sizeof *lv);
+ lv->validator = lvf;
+ lv->validationFunctionName = lvfName;
+ lv->context = context;
+ lv->next = listValidators;
+ listValidators = lv;
+}
+
+mDNSlocal void validateLists(void)
+{
+ mDNSListValidator *vfp;
+ // Check Unix Domain Socket client lists (uds_daemon.c)
+ for (vfp = listValidators; vfp; vfp = vfp->next)
+ {
+ vfp->validator(vfp->context);
+ }
+
+ mDNSPlatformValidateLists();
+}
+
+#define kAllocMagic 0xDEAD1234
+#define kGuardMagic 0xDEAD1234
+#define kFreeMagic 0xDEADDEAD
+#define kAllocLargeSize 32768
+
+mDNSexport void *mallocL(const char *msg, mDNSu32 size)
+{
+ // Allocate space for two words of sanity checking data before the requested block and two words after.
+ // Adjust the length for alignment.
+ mDNSu32 *mem = malloc(sizeof(mDNSu32) * 4 + size);
+ mDNSu32 guard[2];
+ if (!mem)
+ { LogMsg("malloc( %s : %u ) failed", msg, size); return(NULL); }
+ else
+ {
+ mDNSu32 *after = (mDNSu32 *)((mDNSu8 *)(mem + 2) + size);
+ if (size > kAllocLargeSize) LogMsg("malloc( %s : %lu ) @ %p suspiciously large", msg, size, &mem[2]);
+ else if (MDNS_MALLOC_DEBUGGING >= 2) LogMsg("malloc( %s : %lu ) @ %p", msg, size, &mem[2]);
+ mem[ 0] = kAllocMagic;
+ guard[0] = kGuardMagic;
+ mem[ 1] = size;
+ guard[1] = size;
+ memcpy(after, &guard, sizeof guard);
+ memset(&mem[2], 0xFF, size);
+ validateLists();
+ return(&mem[2]);
+ }
+}
+
+mDNSexport void *callocL(const char *msg, mDNSu32 size)
+{
+ mDNSu32 guard[2];
+ const mDNSu32 headerSize = 4 * sizeof(mDNSu32);
+
+ // Allocate space for two words of sanity checking data before the requested block and two words after.
+ // Adjust the length for alignment.
+ mDNSu32 *mem = (mDNSu32 *)calloc(1, headerSize + size);
+ if (!mem)
+ { LogMsg("calloc( %s : %u ) failed", msg, size); return(NULL); }
+ else
+ {
+ mDNSu32 *after = (mDNSu32 *)((mDNSu8 *)(mem + 2) + size);
+ if (size > kAllocLargeSize) LogMsg("calloc( %s : %lu ) @ %p suspiciously large", msg, size, &mem[2]);
+ else if (MDNS_MALLOC_DEBUGGING >= 2) LogMsg("calloc( %s : %lu ) @ %p", msg, size, &mem[2]);
+ mem[ 0] = kAllocMagic;
+ guard[0] = kGuardMagic;
+ mem[ 1] = size;
+ guard[1] = size;
+ memcpy(after, guard, sizeof guard);
+ validateLists();
+ return(&mem[2]);
+ }
+}
+
+mDNSexport void freeL(const char *msg, void *x)
+{
+ if (!x)
+ LogMsg("free( %s @ NULL )!", msg);
+ else
+ {
+ mDNSu32 *mem = ((mDNSu32 *)x) - 2;
+ if (mem[0] == kFreeMagic) { LogMemCorruption("free( %s : %lu @ %p ) !!!! ALREADY DISPOSED !!!!", msg, mem[1], &mem[2]); return; }
+ if (mem[0] != kAllocMagic) { LogMemCorruption("free( %s : %lu @ %p ) !!!! NEVER ALLOCATED !!!!", msg, mem[1], &mem[2]); return; }
+ if (mem[1] > kAllocLargeSize) LogMsg("free( %s : %lu @ %p) suspiciously large", msg, mem[1], &mem[2]);
+ else if (MDNS_MALLOC_DEBUGGING >= 2) LogMsg("free( %s : %ld @ %p)", msg, mem[1], &mem[2]);
+ mDNSu32 *after = (mDNSu32 *)((mDNSu8 *)x + mem[1]);
+ mDNSu32 guard[2];
+
+ memcpy(guard, after, sizeof guard);
+ if (guard[0] != kGuardMagic) { LogMemCorruption("free( %s : %lu @ %p ) !!!! END GUARD OVERWRITE !!!!",
+ msg, mem[1], &mem[2]); return; }
+ if (guard[1] != mem[1]) { LogMemCorruption("free( %s : %lu @ %p ) !!!! LENGTH MISMATCH !!!!",
+ msg, mem[1], &mem[2]); return; }
+ mem[0] = kFreeMagic;
+ memset(mem + 2, 0xFF, mem[1] + 2 * sizeof(mDNSu32));
+ validateLists();
+ free(mem);
+ }
+}
+
+#endif
+
// Bind a UDP socket to find the source address to a destination
mDNSexport void mDNSPlatformSourceAddrForDest(mDNSAddr *const src, const mDNSAddr *const dst)
{
@@ -89,7 +217,7 @@ exit:
mDNSlocal mDNSBool GetConfigOption(char *dst, const char *option, FILE *f)
{
char buf[32+1+MAX_ESCAPED_DOMAIN_NAME]; // Option name, one space, option value
- unsigned int len = strlen(option);
+ size_t len = strlen(option);
if (len + 1 + MAX_ESCAPED_DOMAIN_NAME > sizeof(buf)-1) { LogMsg("GetConfigOption: option %s too long", option); return mDNSfalse; }
fseek(f, 0, SEEK_SET); // set position to beginning of stream
while (fgets(buf, sizeof(buf), f)) // Read at most sizeof(buf)-1 bytes from file, and append '\0' C-string terminator
@@ -135,9 +263,9 @@ mDNSexport void ReadDDNSSettingsFromConfFile(mDNS *const m, const char *const fi
if (domain && domain->c[0] && buf[0])
{
- DomainAuthInfo *info = (DomainAuthInfo*)mDNSPlatformMemAllocate(sizeof(*info));
+ DomainAuthInfo *info = (DomainAuthInfo*) mDNSPlatformMemAllocateClear(sizeof(*info));
// for now we assume keyname = service reg domain and we use same key for service and hostname registration
- err = mDNS_SetSecretForDomain(m, info, domain, domain, buf, NULL, 0, mDNSfalse);
+ err = mDNS_SetSecretForDomain(m, info, domain, domain, buf, NULL, 0);
if (err) LogMsg("ERROR: mDNS_SetSecretForDomain returned %d for domain %##s", err, domain->c);
}
@@ -156,6 +284,7 @@ mDNSexport void mDNSPlatformWriteDebugMsg(const char *msg)
}
#endif
+#if !MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
mDNSexport void mDNSPlatformWriteLogMsg(const char *ident, const char *buffer, mDNSLogLevel_t loglevel)
{
#if APPLE_OSX_mDNSResponder && LogTimeStamps
@@ -179,26 +308,16 @@ mDNSexport void mDNSPlatformWriteLogMsg(const char *ident, const char *buffer, m
{
static int log_inited = 0;
- int syslog_level = LOG_ERR;
+ int syslog_level;
switch (loglevel)
{
-#if APPLE_OSX_mDNSResponder
- case MDNS_LOG_MSG: syslog_level = OS_LOG_TYPE_DEFAULT; break;
- case MDNS_LOG_OPERATION: syslog_level = OS_LOG_TYPE_INFO; break;
- case MDNS_LOG_SPS: syslog_level = OS_LOG_TYPE_INFO; break;
- case MDNS_LOG_INFO: syslog_level = OS_LOG_TYPE_INFO; break;
- case MDNS_LOG_DEBUG: syslog_level = OS_LOG_TYPE_DEBUG; break;
- default: syslog_level = OS_LOG_TYPE_DEFAULT; break;
-#else
- case MDNS_LOG_MSG: syslog_level = LOG_ERR; break;
- case MDNS_LOG_OPERATION: syslog_level = LOG_WARNING; break;
- case MDNS_LOG_SPS: syslog_level = LOG_NOTICE; break;
- case MDNS_LOG_INFO: syslog_level = LOG_INFO; break;
- case MDNS_LOG_DEBUG: syslog_level = LOG_DEBUG; break;
- default:
- fprintf(stderr, "Unknown loglevel %d, assuming LOG_ERR\n", loglevel);
- fflush(stderr);
-#endif
+ case MDNS_LOG_FAULT: syslog_level = LOG_ERR; break;
+ case MDNS_LOG_ERROR: syslog_level = LOG_ERR; break;
+ case MDNS_LOG_WARNING: syslog_level = LOG_WARNING; break;
+ case MDNS_LOG_DEFAULT: syslog_level = LOG_NOTICE; break;
+ case MDNS_LOG_INFO: syslog_level = LOG_INFO; break;
+ case MDNS_LOG_DEBUG: syslog_level = LOG_DEBUG; break;
+ default: syslog_level = LOG_NOTICE; break;
}
if (!log_inited) { openlog(ident, LOG_CONS, LOG_DAEMON); log_inited++; }
@@ -209,11 +328,412 @@ mDNSexport void mDNSPlatformWriteLogMsg(const char *ident, const char *buffer, m
else
#endif
{
-#if APPLE_OSX_mDNSResponder
- mDNSPlatformLogToFile(syslog_level, buffer);
-#else
syslog(syslog_level, "%s", buffer);
+ }
+ }
+}
+#endif // !MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+
+mDNSexport mDNSBool mDNSPosixTCPSocketSetup(int *fd, mDNSAddr_Type addrType, mDNSIPPort *port, mDNSIPPort *outTcpPort)
+{
+ int sa_family = (addrType == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
+ int err;
+ int sock;
+ mDNSu32 lowWater = 15384;
+
+ sock = socket(sa_family, SOCK_STREAM, IPPROTO_TCP);
+ if (sock < 3)
+ {
+ if (errno != EAFNOSUPPORT)
+ {
+ LogMsg("mDNSPosixTCPSocketSetup: socket error %d errno %d (%s)", sock, errno, strerror(errno));
+ }
+ return mDNStrue;
+ }
+ *fd = sock;
+
+ union
+ {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ } addr;
+ // If port is not NULL, bind to it.
+ if (port != NULL)
+ {
+ socklen_t len = (sa_family == AF_INET) ? sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6);
+ mDNSPlatformMemZero(&addr, sizeof addr);
+
+ addr.sa.sa_family = sa_family;
+#ifndef NOT_HAVE_SA_LEN
+ addr.sa.sa_len = len;
#endif
+ if (sa_family == AF_INET6)
+ {
+ addr.sin6.sin6_port = port->NotAnInteger;
}
+ else
+ {
+ addr.sin.sin_port = port->NotAnInteger;
+ }
+ err = bind(sock, &addr.sa, len);
+ if (err < 0)
+ {
+ LogMsg("mDNSPosixTCPSocketSetup getsockname: %s", strerror(errno));
+ return mDNSfalse;
+ }
+ }
+
+ socklen_t addrlen = sizeof addr;
+ err = getsockname(sock, (struct sockaddr *)&addr, &addrlen);
+ if (err < 0)
+ {
+ LogMsg("mDNSPosixTCPSocketSetup getsockname: %s", strerror(errno));
+ return mDNSfalse;
+ }
+ if (sa_family == AF_INET6)
+ {
+ outTcpPort->NotAnInteger = addr.sin6.sin6_port;
+
+ } else
+ {
+ outTcpPort->NotAnInteger = addr.sin.sin_port;
+ }
+ if (port)
+ port->NotAnInteger = outTcpPort->NotAnInteger;
+
+#ifdef TCP_NOTSENT_LOWAT
+ err = setsockopt(sock, IPPROTO_TCP, TCP_NOTSENT_LOWAT, &lowWater, sizeof lowWater);
+ if (err < 0)
+ {
+ LogMsg("mDNSPosixTCPSocketSetup: TCP_NOTSENT_LOWAT failed: %s", strerror(errno));
+ return mDNSfalse;
+ }
+#endif
+
+ return mDNStrue;
+}
+
+mDNSexport TCPSocket *mDNSPosixDoTCPListenCallback(int fd, mDNSAddr_Type addressType, TCPSocketFlags socketFlags,
+ TCPAcceptedCallback callback, void *context)
+{
+ union
+ {
+ struct sockaddr_in6 sin6;
+ struct sockaddr_in sin;
+ struct sockaddr sa;
+ } address;
+
+ socklen_t slen = sizeof address;
+ int remoteSock;
+ mDNSAddr addr;
+ mDNSIPPort port;
+ TCPSocket *sock = mDNSNULL;
+ int failed;
+ char *nbp;
+ int i;
+ mDNSu32 lowWater = 16384;
+ // When we remember our connection, we remember a name that we can print for logging. But
+ // since we are the listener in this case, we don't /have/ a name for it. This buffer
+ // is used to print the IP address into a human readable string which will serve that purpose
+ // for this case.
+ char namebuf[INET6_ADDRSTRLEN + 1 + 5 + 1];
+
+ remoteSock = accept(fd, &address.sa, &slen);
+ if (remoteSock < 0)
+ {
+ LogMsg("mDNSPosixDoTCPListenCallback: accept returned %d", remoteSock);
+ goto out;
+ }
+
+ failed = fcntl(remoteSock, F_SETFL, O_NONBLOCK);
+ if (failed < 0)
+ {
+ close(remoteSock);
+ LogMsg("mDNSPosixDoTCPListenCallback: fcntl returned %d", errno);
+ goto out;
+ }
+
+#ifdef TCP_NOTSENT_LOWAT
+ failed = setsockopt(remoteSock, IPPROTO_TCP, TCP_NOTSENT_LOWAT,
+ &lowWater, sizeof lowWater);
+ if (failed < 0)
+ {
+ close(remoteSock);
+ LogMsg("mDNSPosixDoTCPListenCallback: TCP_NOTSENT_LOWAT returned %d", errno);
+ goto out;
+ }
+#endif
+
+ if (address.sa.sa_family == AF_INET6)
+ {
+ // If we are listening on an IPv4/IPv6 socket, the incoming address might be an IPv4-in-IPv6 address
+ for (i = 0; i < 10; i++)
+ {
+ if (address.sin6.sin6_addr.s6_addr[i] != 0)
+ {
+ addr.type = mDNSAddrType_IPv6;
+ goto nope;
+ }
+ }
+
+ // a legit IPv4 address would be ::ffff:a.b.c.d; if there's no ::ffff bit, then it's an IPv6
+ // address with a really weird prefix.
+ if (address.sin6.sin6_addr.s6_addr[10] != 0xFF || address.sin6.sin6_addr.s6_addr[11] != 0xFF)
+ {
+ addr.type = mDNSAddrType_IPv6;
+ } else if (addressType != mDNSAddrType_None)
+ {
+ if (inet_ntop(AF_INET, &address.sin6.sin6_addr.s6_addr[12], namebuf, INET6_ADDRSTRLEN + 1) == NULL)
+ {
+ strcpy(namebuf, ":unknown:");
+ }
+ LogMsg("mDNSPosixDoTCPListenCallback received an IPv4 connection from %s on an IPv6-only socket.",
+ namebuf);
+ close(remoteSock);
+ goto out;
+ }
+ else
+ {
+ addr.type = mDNSAddrType_IPv4;
+ }
+ nope:
+ if (addr.type == mDNSAddrType_IPv6)
+ {
+ if (inet_ntop(address.sin6.sin6_family, &address.sin6.sin6_addr, namebuf, INET6_ADDRSTRLEN + 1) == NULL)
+ {
+ strcpy(namebuf, ":unknown:");
+ }
+ memcpy(&addr.ip.v6, &address.sin6.sin6_addr, sizeof addr.ip.v6);
+ }
+ else
+ {
+ if (inet_ntop(AF_INET, &address.sin6.sin6_addr.s6_addr[12], namebuf, INET6_ADDRSTRLEN + 1) == NULL)
+ {
+ strcpy(namebuf, ":unknown:");
+ }
+ memcpy(&addr.ip.v4, &address.sin6.sin6_addr.s6_addr[12], sizeof addr.ip.v4);
+ }
+ port.NotAnInteger = address.sin6.sin6_port;
+ }
+ else if (address.sa.sa_family == AF_INET)
+ {
+ addr.type = mDNSAddrType_IPv4;
+ memcpy(&addr.ip.v4, &address.sin.sin_addr, sizeof addr.ip.v4);
+ port.NotAnInteger = address.sin.sin_port;
+ if (inet_ntop(AF_INET, &address.sin.sin_addr, namebuf, INET6_ADDRSTRLEN + 1) == NULL)
+ {
+ strcpy(namebuf, ":unknown:");
+ }
+ } else {
+ LogMsg("mDNSPosixDoTCPListenCallback: connection from unknown address family %d", address.sa.sa_family);
+ close(remoteSock);
+ goto out;
+ }
+ nbp = namebuf + strlen(namebuf);
+ *nbp++ = '%';
+ snprintf(nbp, 6, "%u", ntohs(port.NotAnInteger));
+
+ sock = mDNSPlatformTCPAccept(socketFlags, remoteSock);
+ if (sock == NULL)
+ {
+ LogMsg("mDNSPosixDoTCPListenCallback: mDNSPlatformTCPAccept returned NULL; dropping connection from %s",
+ namebuf);
+ close(remoteSock);
+ goto out;
+ }
+ callback(sock, &addr, &port, namebuf, context);
+out:
+ return sock;
+}
+
+mDNSexport mDNSBool mDNSPosixTCPListen(int *fd, mDNSAddr_Type addrtype, mDNSIPPort *port, mDNSAddr *addr,
+ mDNSBool reuseAddr, int queueLength)
+
+{
+ union
+ {
+ struct sockaddr_in6 sin6;
+ struct sockaddr_in sin;
+ struct sockaddr sa;
+ } address;
+
+ int failed;
+ int sock;
+ int one = 1;
+ socklen_t sock_len;
+
+ // We require an addrtype parameter because addr is allowed to be null, but they have to agree.
+ if (addr != mDNSNULL && addr->type != addrtype)
+ {
+ LogMsg("mDNSPlatformTCPListen: address type conflict: %d:%d", addr->type, addrtype);
+ return mDNSfalse;
+ }
+ if (port == mDNSNULL)
+ {
+ LogMsg("mDNSPlatformTCPListen: port must not be NULL");
+ return mDNSfalse;
+ }
+
+ mDNSPlatformMemZero(&address, sizeof address);
+ if (addrtype == mDNSAddrType_None || addrtype == mDNSAddrType_IPv6)
+ {
+ // Set up DNS listener socket
+ if (addr != mDNSNULL)
+ {
+ memcpy(&address.sin6.sin6_addr.s6_addr, &addr->ip, sizeof address.sin6.sin6_addr.s6_addr);
+ }
+ address.sin6.sin6_port = port->NotAnInteger;
+
+ sock_len = sizeof address.sin6;
+ address.sin6.sin6_family = AF_INET6;
+ }
+ else if (addrtype == mDNSAddrType_IPv4)
+ {
+ if (addr != mDNSNULL)
+ {
+ memcpy(&address.sin.sin_addr.s_addr, &addr->ip, sizeof address.sin.sin_addr.s_addr);
+ }
+ address.sin.sin_port = port->NotAnInteger;
+ sock_len = sizeof address.sin;
+ address.sin.sin_family = AF_INET;
+ }
+ else
+ {
+ LogMsg("mDNSPlatformTCPListen: invalid address type: %d", addrtype);
+ return mDNSfalse;
+ }
+#ifndef NOT_HAVE_SA_LEN
+ address.sa.sa_len = sock_len;
+#endif
+ sock = socket(address.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
+
+ if (sock < 0)
+ {
+ LogMsg("mDNSPlatformTCPListen: socket call failed: %s", strerror(errno));
+ return mDNSfalse;
+ }
+ *fd = sock;
+
+ // The reuseAddr flag is used to indicate that we want to listen on this port even if
+ // there are still lingering sockets. We will still fail if there is another listener.
+ // Note that this requires SO_REUSEADDR, not SO_REUSEPORT, which does not have special
+ // handling for lingering sockets.
+ if (reuseAddr)
+ {
+ failed = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one);
+ if (failed < 0)
+ {
+ LogMsg("mDNSPlatformTCPListen: SO_REUSEADDR failed %s", strerror(errno));
+ return mDNSfalse;
+ }
+ }
+
+ // Bind to the port and (if provided) address
+ failed = bind(sock, &address.sa, sock_len);
+ if (failed < 0)
+ {
+ LogMsg("mDNSPlatformTCPListen: bind failed %s", strerror(errno));
+ return mDNSfalse;
+ }
+
+ // If there was no specified listen port, we need to know what port we got.
+ if (port->NotAnInteger == 0)
+ {
+ mDNSPlatformMemZero(&address, sizeof address);
+ failed = getsockname(sock, &address.sa, &sock_len);
+ if (failed < 0)
+ {
+ LogMsg("mDNSRelay: getsockname failed: %s", strerror(errno));
+ return mDNSfalse;
+ }
+ if (address.sa.sa_family == AF_INET)
+ {
+ port->NotAnInteger = address.sin.sin_port;
+ }
+ else
+ {
+ port->NotAnInteger = address.sin6.sin6_port;
+ }
+ }
+
+ failed = listen(sock, queueLength);
+ if (failed < 0)
+ {
+ LogMsg("mDNSPlatformTCPListen: listen failed: %s", strerror(errno));
+ return mDNSfalse;
+ }
+ return mDNStrue;
+}
+
+mDNSexport long mDNSPosixReadTCP(int fd, void *buf, unsigned long buflen, mDNSBool *closed)
+{
+ static int CLOSEDcount = 0;
+ static int EAGAINcount = 0;
+ ssize_t nread = recv(fd, buf, buflen, 0);
+
+ if (nread > 0)
+ {
+ CLOSEDcount = 0;
+ EAGAINcount = 0;
+ } // On success, clear our error counters
+ else if (nread == 0)
+ {
+ *closed = mDNStrue;
+ if ((++CLOSEDcount % 20) == 0)
+ {
+ LogMsg("ERROR: mDNSPosixReadFromSocket - recv %d got CLOSED %d times", fd, CLOSEDcount);
+ assert(CLOSEDcount < 1000);
+ // Recovery Mechanism to bail mDNSResponder out of trouble: Instead of logging the same error
+ // msg multiple times, crash mDNSResponder using assert() and restart fresh. See advantages
+ // below:
+ // 1.Better User Experience
+ // 2.CrashLogs frequency can be monitored
+ // 3.StackTrace can be used for more info
+ }
+ }
+ // else nread is negative -- see what kind of error we got
+ else if (errno == ECONNRESET)
+ {
+ nread = 0; *closed = mDNStrue;
+ }
+ else if (errno != EAGAIN)
+ {
+ LogMsg("ERROR: mDNSPosixReadFromSocket - recv: %d (%s)", errno, strerror(errno));
+ nread = -1;
+ }
+ else
+ { // errno is EAGAIN (EWOULDBLOCK) -- no data available
+ nread = 0;
+ if ((++EAGAINcount % 1000) == 0)
+ {
+ LogMsg("ERROR: mDNSPosixReadFromSocket - recv %d got EAGAIN %d times", fd, EAGAINcount);
+ sleep(1);
+ }
+ }
+ return nread;
+}
+
+mDNSexport long mDNSPosixWriteTCP(int fd, const char *msg, unsigned long len)
+{
+ ssize_t result;
+ long nsent;
+
+ result = write(fd, msg, len);
+ if (result < 0)
+ {
+ if (errno == EAGAIN)
+ {
+ nsent = 0;
+ }
+ else
+ {
+ LogMsg("ERROR: mDNSPosixWriteTCP - send %s", strerror(errno)); nsent = -1;
+ }
+ }
+ else
+ {
+ nsent = (long)result;
}
+ return nsent;
}
diff --git a/usr/src/contrib/mDNSResponder/mDNSShared/PlatformCommon.h b/usr/src/contrib/mDNSResponder/mDNSShared/PlatformCommon.h
index 2a068711e0..fae414ae4c 100644
--- a/usr/src/contrib/mDNSResponder/mDNSShared/PlatformCommon.h
+++ b/usr/src/contrib/mDNSResponder/mDNSShared/PlatformCommon.h
@@ -1,4 +1,4 @@
-/* -*- Mode: C; tab-width: 4 -*-
+/* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*-
*
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
@@ -15,4 +15,16 @@
* limitations under the License.
*/
-extern void ReadDDNSSettingsFromConfFile(mDNS *const m, const char *const filename, domainname *const hostname, domainname *const domain, mDNSBool *DomainDiscoveryDisabled);
+#ifndef __PLATFORM_COMMON_H
+#define __PLATFORM_COMMON_H
+extern void ReadDDNSSettingsFromConfFile(mDNS *const m, const char *const filename,
+ domainname *const hostname, domainname *const domain,
+ mDNSBool *DomainDiscoveryDisabled);
+extern mDNSBool mDNSPosixTCPSocketSetup(int *fd, mDNSAddr_Type addrType, mDNSIPPort *port, mDNSIPPort *outTcpPort);
+extern TCPSocket *mDNSPosixDoTCPListenCallback(int fd, mDNSAddr_Type addressType, TCPSocketFlags socketFlags,
+ TCPAcceptedCallback callback, void *context);
+extern mDNSBool mDNSPosixTCPListen(int *fd, mDNSAddr_Type addrtype, mDNSIPPort *port, mDNSAddr *addr,
+ mDNSBool reuseAddr, int queueLength);
+extern long mDNSPosixReadTCP(int fd, void *buf, unsigned long buflen, mDNSBool *closed);
+extern long mDNSPosixWriteTCP(int fd, const char *msg, unsigned long len);
+#endif
diff --git a/usr/src/contrib/mDNSResponder/mDNSShared/dns_sd.h b/usr/src/contrib/mDNSResponder/mDNSShared/dns_sd.h
index 0a4597fae0..690178ac7e 100644
--- a/usr/src/contrib/mDNSResponder/mDNSShared/dns_sd.h
+++ b/usr/src/contrib/mDNSResponder/mDNSShared/dns_sd.h
@@ -66,7 +66,7 @@
*/
#ifndef _DNS_SD_H
-#define _DNS_SD_H 8806001
+#define _DNS_SD_H 13108001
#ifdef __cplusplus
extern "C" {
@@ -197,7 +197,7 @@ enum
kDNSServiceFlagsAutoTrigger = 0x1,
/* Valid for browses using kDNSServiceInterfaceIndexAny.
- * Will auto trigger the browse over AWDL as well once the service is discoveryed
+ * Will auto trigger the browse over AWDL as well once the service is discovered
* over BLE.
* This flag is an input value to DNSServiceBrowse(), which is why we can
* use the same value as kDNSServiceFlagsMoreComing, which is an output flag
@@ -256,7 +256,6 @@ enum
/*
* Client guarantees that record names are unique, so we can skip sending out initial
* probe messages. Standard name conflict resolution is still done if a conflict is discovered.
- * Currently only valid for a DNSServiceRegister call.
*/
kDNSServiceFlagsReturnIntermediates = 0x1000,
@@ -273,38 +272,28 @@ enum
* (In earlier builds this flag was briefly calledkDNSServiceFlagsReturnCNAME)
*/
- kDNSServiceFlagsNonBrowsable = 0x2000,
- /* A service registered with the NonBrowsable flag set can be resolved using
- * DNSServiceResolve(), but will not be discoverable using DNSServiceBrowse().
- * This is for cases where the name is actually a GUID; it is found by other means;
- * there is no end-user benefit to browsing to find a long list of opaque GUIDs.
- * Using the NonBrowsable flag creates SRV+TXT without the cost of also advertising
- * an associated PTR record.
- */
-
kDNSServiceFlagsShareConnection = 0x4000,
/* For efficiency, clients that perform many concurrent operations may want to use a
* single Unix Domain Socket connection with the background daemon, instead of having a
* separate connection for each independent operation. To use this mode, clients first
- * call DNSServiceCreateConnection(&MainRef) to initialize the main DNSServiceRef.
+ * call DNSServiceCreateConnection(&SharedRef) to initialize the main DNSServiceRef.
* For each subsequent operation that is to share that same connection, the client copies
- * the MainRef, and then passes the address of that copy, setting the ShareConnection flag
+ * the SharedRef, and then passes the address of that copy, setting the ShareConnection flag
* to tell the library that this DNSServiceRef is not a typical uninitialized DNSServiceRef;
* it's a copy of an existing DNSServiceRef whose connection information should be reused.
*
* For example:
*
* DNSServiceErrorType error;
- * DNSServiceRef MainRef;
- * error = DNSServiceCreateConnection(&MainRef);
+ * DNSServiceRef SharedRef;
+ * error = DNSServiceCreateConnection(&SharedRef);
* if (error) ...
- * DNSServiceRef BrowseRef = MainRef; // Important: COPY the primary DNSServiceRef first...
+ * DNSServiceRef BrowseRef = SharedRef; // Important: COPY the primary DNSServiceRef first...
* error = DNSServiceBrowse(&BrowseRef, kDNSServiceFlagsShareConnection, ...); // then use the copy
* if (error) ...
* ...
* DNSServiceRefDeallocate(BrowseRef); // Terminate the browse operation
- * DNSServiceRefDeallocate(MainRef); // Terminate the shared connection
- * Also see Point 4.(Don't Double-Deallocate if the MainRef has been Deallocated) in Notes below:
+ * DNSServiceRefDeallocate(SharedRef); // Terminate the shared connection
*
* Notes:
*
@@ -342,15 +331,18 @@ enum
* DNSServiceRef's created by other calls like DNSServiceBrowse() or DNSServiceResolve()
* cannot be shared by copying them and using kDNSServiceFlagsShareConnection.
*
- * 4. Don't Double-Deallocate if the MainRef has been Deallocated
- * Calling DNSServiceRefDeallocate(ref) for a particular operation's DNSServiceRef terminates
- * just that operation. Calling DNSServiceRefDeallocate(ref) for the main shared DNSServiceRef
- * (the parent DNSServiceRef, originally created by DNSServiceCreateConnection(&ref))
- * automatically terminates the shared connection and all operations that were still using it.
+ * 4. Don't Double-Deallocate
+ * Calling DNSServiceRefDeallocate(OpRef) for a particular operation's DNSServiceRef terminates
+ * just that operation. Calling DNSServiceRefDeallocate(SharedRef) for the main shared DNSServiceRef
+ * (the parent DNSServiceRef, originally created by DNSServiceCreateConnection(&SharedRef))
+ * automatically terminates the shared connection *and* all operations that were still using it.
* After doing this, DO NOT then attempt to deallocate any remaining subordinate DNSServiceRef's.
* The memory used by those subordinate DNSServiceRef's has already been freed, so any attempt
* to do a DNSServiceRefDeallocate (or any other operation) on them will result in accesses
* to freed memory, leading to crashes or other equally undesirable results.
+ * You can deallocate individual operations first and then deallocate the parent DNSServiceRef last,
+ * but if you deallocate the parent DNSServiceRef first, then all of the subordinate DNSServiceRef's
+ * are implicitly deallocated, and explicitly deallocating them a second time will lead to crashes.
*
* 5. Thread Safety
* The dns_sd.h API does not presuppose any particular threading model, and consequently
@@ -358,15 +350,15 @@ enum
* If the client concurrently, from multiple threads (or contexts), calls API routines using
* the same DNSServiceRef, it is the client's responsibility to provide mutual exclusion for
* that DNSServiceRef.
-
+ *
* For example, use of DNSServiceRefDeallocate requires caution. A common mistake is as follows:
* Thread B calls DNSServiceRefDeallocate to deallocate sdRef while Thread A is processing events
* using sdRef. Doing this will lead to intermittent crashes on thread A if the sdRef is used after
* it was deallocated.
-
+ *
* A telltale sign of this crash type is to see DNSServiceProcessResult on the stack preceding the
* actual crash location.
-
+ *
* To state this more explicitly, mDNSResponder does not queue DNSServiceRefDeallocate so
* that it occurs discretely before or after an event is handled.
*/
@@ -414,6 +406,12 @@ enum
* Include AWDL interface when kDNSServiceInterfaceIndexAny is specified.
*/
+ kDNSServiceFlagsEnableDNSSEC = 0x200000,
+ /*
+ * Perform DNSSEC validation on the client request when kDNSServiceFlagsEnableDNSSEC is specified
+ * Since the client API has not been finalized, we will use it as a temporary flag to turn on the DNSSEC validation.
+ */
+
kDNSServiceFlagsValidate = 0x200000,
/*
* This flag is meaningful in DNSServiceGetAddrInfo and DNSServiceQueryRecord. This is the ONLY flag to be valid
@@ -434,8 +432,8 @@ enum
* kDNSServiceFlagsAdd and kDNSServiceFlagsValidate.
*
* The following four flags indicate the status of the DNSSEC validation and marked in the flags field of the callback.
- * When any of the four flags is set, kDNSServiceFlagsValidate will also be set. To check the validation status, the
- * other applicable output flags should be masked. See kDNSServiceOutputFlags below.
+ * When any of the four flags is set, kDNSServiceFlagsValidate will also be set. To check the validation status, the
+ * other applicable output flags should be masked.
*/
kDNSServiceFlagsSecure = 0x200010,
@@ -519,26 +517,38 @@ enum
* is only set in the callbacks and kDNSServiceFlagsThresholdOne is only set on
* input to a DNSServiceBrowse call.
*/
- kDNSServiceFlagsPrivateOne = 0x8000000,
+ kDNSServiceFlagsPrivateOne = 0x2000,
+ /*
+ * This flag is private and should not be used.
+ */
+
+ kDNSServiceFlagsPrivateTwo = 0x8000000,
/*
* This flag is private and should not be used.
*/
- kDNSServiceFlagsPrivateTwo = 0x10000000,
+ kDNSServiceFlagsPrivateThree = 0x10000000,
/*
* This flag is private and should not be used.
*/
- kDNSServiceFlagsPrivateThree = 0x20000000,
+ kDNSServiceFlagsPrivateFour = 0x20000000,
/*
* This flag is private and should not be used.
*/
- kDNSServiceFlagsPrivateFour = 0x40000000,
+ kDNSServiceFlagsPrivateFive = 0x40000000,
/*
* This flag is private and should not be used.
*/
+
+ kDNSServiceFlagAnsweredFromCache = 0x40000000,
+ /*
+ * When kDNSServiceFlagAnsweredFromCache is passed back in the flags parameter of DNSServiceQueryRecordReply or DNSServiceGetAddrInfoReply,
+ * an answer will have this flag set if it was answered from the cache.
+ */
+
kDNSServiceFlagsAllowExpiredAnswers = 0x80000000,
/*
* When kDNSServiceFlagsAllowExpiredAnswers is passed to DNSServiceQueryRecord or DNSServiceGetAddrInfo,
@@ -555,9 +565,6 @@ enum
};
-#define kDNSServiceOutputFlags (kDNSServiceFlagsValidate | kDNSServiceFlagsValidateOptional | kDNSServiceFlagsMoreComing | kDNSServiceFlagsAdd | kDNSServiceFlagsDefault)
- /* All the output flags excluding the DNSSEC Status flags. Typically used to check DNSSEC Status */
-
/* Possible protocol values */
enum
{
@@ -647,6 +654,9 @@ enum
kDNSServiceType_HIP = 55, /* Host Identity Protocol */
+ kDNSServiceType_SVCB = 64, /* Service Binding. */
+ kDNSServiceType_HTTPS = 65, /* HTTPS Service Binding. */
+
kDNSServiceType_SPF = 99, /* Sender Policy Framework for E-Mail */
kDNSServiceType_UINFO = 100, /* IANA-Reserved */
kDNSServiceType_UID = 101, /* IANA-Reserved */
@@ -659,7 +669,7 @@ enum
kDNSServiceType_AXFR = 252, /* Transfer zone of authority. */
kDNSServiceType_MAILB = 253, /* Transfer mailbox records. */
kDNSServiceType_MAILA = 254, /* Transfer mail agent records. */
- kDNSServiceType_ANY = 255 /* Wildcard match. */
+ kDNSServiceType_ANY = 255 /* Wildcard match. */
};
/* possible error code values */
@@ -696,7 +706,9 @@ enum
kDNSServiceErr_NATPortMappingDisabled = -65565, /* NAT supports PCP, NAT-PMP or UPnP, but it's disabled by the administrator */
kDNSServiceErr_NoRouter = -65566, /* No router currently configured (probably no network connectivity) */
kDNSServiceErr_PollingMode = -65567,
- kDNSServiceErr_Timeout = -65568
+ kDNSServiceErr_Timeout = -65568,
+ kDNSServiceErr_DefunctConnection = -65569, /* Connection to daemon returned a SO_ISDEFUNCT error result */
+ kDNSServiceErr_PolicyDenied = -65570
/* mDNS Error codes are in the range
* FFFE FF00 (-65792) to FFFE FFFF (-65537) */
@@ -722,8 +734,10 @@ enum
* conventional DNS escaping rules, as used by the traditional DNS res_query() API, as described below:
*
* Generally all UTF-8 characters (which includes all US ASCII characters) represent themselves,
- * with two exceptions, the dot ('.') character, which is the label separator,
- * and the backslash ('\') character, which is the escape character.
+ * with three exceptions:
+ * the dot ('.') character, which is the DNS label separator,
+ * the backslash ('\') character, which is the DNS escape character, and
+ * the ASCII NUL (0) byte value, which is the C-string terminator character.
* The escape character ('\') is interpreted as described below:
*
* '\ddd', where ddd is a three-digit decimal value from 000 to 255,
@@ -732,11 +746,11 @@ enum
* For example, the ASCII code for 'w' is 119, and therefore '\119' is equivalent to 'w'.
* Thus the command "ping '\119\119\119.apple.com'" is the equivalent to the command "ping 'www.apple.com'".
* Nonprinting ASCII characters in the range 0-31 are often represented this way.
- * In particular, the ASCII NUL character (0) cannot appear in a C string because C uses it as the
- * string terminator character, so ASCII NUL in a domain name has to be represented in a C string as '\000'.
+ * In particular, the ASCII NUL character (0) cannot appear in a C-string because C uses it as the
+ * string terminator character, so ASCII NUL in a domain name has to be represented in a C-string as '\000'.
* Other characters like space (ASCII code 32) are sometimes represented as '\032'
- * in contexts where having an actual space character in a C string would be inconvenient.
- *
+ * in contexts where having an actual space character in a C-string would be inconvenient.
+ *
* Otherwise, for all cases where a '\' is followed by anything other than a three-digit decimal value
* from 000 to 255, the character sequence '\x' represents a single literal occurrence of character 'x'.
* This is legal for any character, so, for example, '\w' is equivalent to 'w'.
@@ -751,6 +765,21 @@ enum
* followed by neither a three-digit decimal value from 000 to 255 nor a single character.
* If a lone escape character ('\') does appear as the last character of a string, it is silently ignored.
*
+ * The worse-case length for an escaped domain name is calculated as follows:
+ * The longest legal domain name is 256 bytes in wire format (see RFC 6762, Appendix C, DNS Name Length).
+ * For our calculation of the longest *escaped* domain name, we use
+ * the longest legal domain name, with the most characters escaped.
+ *
+ * We consider a domain name of the form: "label63.label63.label63.label62."
+ * where "label63" is a 63-byte label and "label62" is a 62-byte label.
+ * Counting four label-length bytes, 251 bytes of label data, and the terminating zero,
+ * this makes a total of 256 bytes in wire format, the longest legal domain name.
+ *
+ * If each one of the 251 bytes of label data is represented using '\ddd',
+ * then it takes 251 * 4 = 1004 bytes to represent these in a C-string.
+ * Adding four '.' characters as shown above, plus the C-string terminating
+ * zero at the end, results in a maximum storage requirement of 1009 bytes.
+ *
* The exceptions, that do not use escaping, are the routines where the full
* DNS name of a resource is broken, for convenience, into servicename/regtype/domain.
* In these routines, the "servicename" is NOT escaped. It does not need to be, since
@@ -997,6 +1026,9 @@ DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef);
* is invalidated when this function is called - the DNSRecordRef may not be used in subsequent
* functions.
*
+ * If the reference was passed to DNSServiceSetDispatchQueue(), DNSServiceRefDeallocate() must
+ * be called on the same queue originally passed as an argument to DNSServiceSetDispatchQueue().
+ *
* Note: This call is to be used only with the DNSServiceRef defined by this API.
*
* sdRef: A DNSServiceRef initialized by any of the DNSService calls.
@@ -1061,12 +1093,17 @@ typedef void (DNSSD_API *DNSServiceDomainEnumReply)
/* DNSServiceEnumerateDomains() Parameters:
*
- * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
- * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
- * and the enumeration operation will run indefinitely until the client
- * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ * sdRef: A pointer to an uninitialized DNSServiceRef
+ * (or, if the kDNSServiceFlagsShareConnection flag is used,
+ * a copy of the shared connection reference that is to be used).
+ * If the call succeeds then it initializes (or updates) the DNSServiceRef,
+ * returns kDNSServiceErr_NoError, and the enumeration operation
+ * will remain active indefinitely until the client terminates it
+ * by passing this DNSServiceRef to DNSServiceRefDeallocate()
+ * (or by closing the underlying shared connection, if used).
*
* flags: Possible values are:
+ * kDNSServiceFlagsShareConnection to use a shared connection.
* kDNSServiceFlagsBrowseDomains to enumerate domains recommended for browsing.
* kDNSServiceFlagsRegistrationDomains to enumerate domains recommended
* for registration.
@@ -1154,13 +1191,20 @@ typedef void (DNSSD_API *DNSServiceRegisterReply)
/* DNSServiceRegister() Parameters:
*
- * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
- * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
- * and the registration will remain active indefinitely until the client
- * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ * sdRef: A pointer to an uninitialized DNSServiceRef
+ * (or, if the kDNSServiceFlagsShareConnection flag is used,
+ * a copy of the shared connection reference that is to be used).
+ * If the call succeeds then it initializes (or updates) the DNSServiceRef,
+ * returns kDNSServiceErr_NoError, and the service registration
+ * will remain active indefinitely until the client terminates it
+ * by passing this DNSServiceRef to DNSServiceRefDeallocate()
+ * (or by closing the underlying shared connection, if used).
*
- * flags: Indicates the renaming behavior on name conflict (most applications
- * will pass 0). See flag definitions above for details.
+ * flags: Possible values are:
+ * kDNSServiceFlagsShareConnection to use a shared connection.
+ * Other flags indicate the renaming behavior on name conflict
+ * (not required for most applications).
+ * See flag definitions above for details.
*
* interfaceIndex: If non-zero, specifies the interface on which to register the service
* (the index for a given interface is determined via the if_nametoindex()
@@ -1210,31 +1254,6 @@ typedef void (DNSSD_API *DNSServiceRegisterReply)
*
* % dns-sd -R Test '_test._tcp,s\.one,s\,two,s\\three,s\000four' local 123
*
- * When a service is registered, all the clients browsing for the registered
- * type ("regtype") will discover it. If the discovery should be
- * restricted to a smaller set of well known peers, the service can be
- * registered with additional data (group identifier) that is known
- * only to a smaller set of peers. The group identifier should follow primary
- * service type using a colon (":") as a delimeter. If subtypes are also present,
- * it should be given before the subtype as shown below.
- *
- * % dns-sd -R _test1 _http._tcp:mygroup1 local 1001
- * % dns-sd -R _test2 _http._tcp:mygroup2 local 1001
- * % dns-sd -R _test3 _http._tcp:mygroup3,HasFeatureA local 1001
- *
- * Now:
- * % dns-sd -B _http._tcp:"mygroup1" # will discover only test1
- * % dns-sd -B _http._tcp:"mygroup2" # will discover only test2
- * % dns-sd -B _http._tcp:"mygroup3",HasFeatureA # will discover only test3
- *
- * By specifying the group information, only the members of that group are
- * discovered.
- *
- * The group identifier itself is not sent in clear. Only a hash of the group
- * identifier is sent and the clients discover them anonymously. The group identifier
- * may be up to 256 bytes long and may contain any eight bit values except comma which
- * should be escaped.
- *
* domain: If non-NULL, specifies the domain on which to advertise the service.
* Most applications will not specify a domain, instead automatically
* registering in the default domain(s).
@@ -1478,12 +1497,17 @@ typedef void (DNSSD_API *DNSServiceBrowseReply)
/* DNSServiceBrowse() Parameters:
*
- * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
- * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
- * and the browse operation will run indefinitely until the client
- * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ * sdRef: A pointer to an uninitialized DNSServiceRef
+ * (or, if the kDNSServiceFlagsShareConnection flag is used,
+ * a copy of the shared connection reference that is to be used).
+ * If the call succeeds then it initializes (or updates) the DNSServiceRef,
+ * returns kDNSServiceErr_NoError, and the browse operation
+ * will remain active indefinitely until the client terminates it
+ * by passing this DNSServiceRef to DNSServiceRefDeallocate()
+ * (or by closing the underlying shared connection, if used).
*
- * flags: Currently ignored, reserved for future use.
+ * flags: Possible values are:
+ * kDNSServiceFlagsShareConnection to use a shared connection.
*
* interfaceIndex: If non-zero, specifies the interface on which to browse for services
* (the index for a given interface is determined via the if_nametoindex()
@@ -1495,10 +1519,7 @@ typedef void (DNSSD_API *DNSServiceBrowseReply)
* A client may optionally specify a single subtype to perform filtered browsing:
* e.g. browsing for "_primarytype._tcp,_subtype" will discover only those
* instances of "_primarytype._tcp" that were registered specifying "_subtype"
- * in their list of registered subtypes. Additionally, a group identifier may
- * also be specified before the subtype e.g., _primarytype._tcp:GroupID, which
- * will discover only the members that register the service with GroupID. See
- * DNSServiceRegister for more details.
+ * in their list of registered subtypes.
*
* domain: If non-NULL, specifies the domain on which to browse for services.
* Most applications will not specify a domain, instead browsing on the
@@ -1607,12 +1628,18 @@ typedef void (DNSSD_API *DNSServiceResolveReply)
/* DNSServiceResolve() Parameters
*
- * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
- * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
- * and the resolve operation will run indefinitely until the client
- * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ * sdRef: A pointer to an uninitialized DNSServiceRef
+ * (or, if the kDNSServiceFlagsShareConnection flag is used,
+ * a copy of the shared connection reference that is to be used).
+ * If the call succeeds then it initializes (or updates) the DNSServiceRef,
+ * returns kDNSServiceErr_NoError, and the resolve operation
+ * will remain active indefinitely until the client terminates it
+ * by passing this DNSServiceRef to DNSServiceRefDeallocate()
+ * (or by closing the underlying shared connection, if used).
*
- * flags: Specifying kDNSServiceFlagsForceMulticast will cause query to be
+ * flags: Possible values are:
+ * kDNSServiceFlagsShareConnection to use a shared connection.
+ * Specifying kDNSServiceFlagsForceMulticast will cause query to be
* performed with a link-local mDNS query, even if the name is an
* apparently non-local name (i.e. a name not ending in ".local.")
*
@@ -1729,12 +1756,18 @@ typedef void (DNSSD_API *DNSServiceQueryRecordReply)
/* DNSServiceQueryRecord() Parameters:
*
- * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
- * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
- * and the query operation will run indefinitely until the client
- * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ * sdRef: A pointer to an uninitialized DNSServiceRef
+ * (or, if the kDNSServiceFlagsShareConnection flag is used,
+ * a copy of the shared connection reference that is to be used).
+ * If the call succeeds then it initializes (or updates) the DNSServiceRef,
+ * returns kDNSServiceErr_NoError, and the query operation
+ * will remain active indefinitely until the client terminates it
+ * by passing this DNSServiceRef to DNSServiceRefDeallocate()
+ * (or by closing the underlying shared connection, if used).
*
- * flags: kDNSServiceFlagsForceMulticast or kDNSServiceFlagsLongLivedQuery.
+ * flags: Possible values are:
+ * kDNSServiceFlagsShareConnection to use a shared connection.
+ * kDNSServiceFlagsForceMulticast or kDNSServiceFlagsLongLivedQuery.
* Pass kDNSServiceFlagsLongLivedQuery to create a "long-lived" unicast
* query to a unicast DNS server that implements the protocol. This flag
* has no effect on link-local multicast queries.
@@ -1835,12 +1868,18 @@ typedef void (DNSSD_API *DNSServiceGetAddrInfoReply)
/* DNSServiceGetAddrInfo() Parameters:
*
- * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds then it
- * initializes the DNSServiceRef, returns kDNSServiceErr_NoError, and the query
- * begins and will last indefinitely until the client terminates the query
- * by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ * sdRef: A pointer to an uninitialized DNSServiceRef
+ * (or, if the kDNSServiceFlagsShareConnection flag is used,
+ * a copy of the shared connection reference that is to be used).
+ * If the call succeeds then it initializes (or updates) the DNSServiceRef,
+ * returns kDNSServiceErr_NoError, and the address query operation
+ * will remain active indefinitely until the client terminates it
+ * by passing this DNSServiceRef to DNSServiceRefDeallocate()
+ * (or by closing the underlying shared connection, if used).
*
- * flags: kDNSServiceFlagsForceMulticast
+ * flags: Possible values are:
+ * kDNSServiceFlagsShareConnection to use a shared connection.
+ * kDNSServiceFlagsForceMulticast
*
* interfaceIndex: The interface on which to issue the query. Passing 0 causes the query to be
* sent on all active interfaces via Multicast or the primary interface via Unicast.
@@ -1896,13 +1935,14 @@ DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo
*
* Parameters:
*
- * sdRef: A pointer to an uninitialized DNSServiceRef. Deallocating
- * the reference (via DNSServiceRefDeallocate()) severs the
- * connection and deregisters all records registered on this connection.
+ * sdRef: A pointer to an uninitialized DNSServiceRef.
+ * Deallocating the reference (via DNSServiceRefDeallocate())
+ * severs the connection and cancels all operations and
+ * deregisters all records registered on this connection.
*
* return value: Returns kDNSServiceErr_NoError on success, otherwise returns
- * an error code indicating the specific failure that occurred (in which
- * case the DNSServiceRef is not initialized).
+ * an error code indicating the specific failure that occurred
+ * (in which case the DNSServiceRef is not initialized).
*/
DNSSD_EXPORT
@@ -1954,8 +1994,7 @@ typedef void (DNSSD_API *DNSServiceRegisterRecordReply)
* and deallocate each of their corresponding DNSServiceRecordRefs, call
* DNSServiceRefDeallocate()).
*
- * flags: Possible values are kDNSServiceFlagsShared or kDNSServiceFlagsUnique
- * (see flag type definitions for details).
+ * flags: One of either kDNSServiceFlagsShared, kDNSServiceFlagsUnique or kDNSServiceFlagsKnownUnique must be set.
*
* interfaceIndex: If non-zero, specifies the interface on which to register the record
* (the index for a given interface is determined via the if_nametoindex()
@@ -2175,15 +2214,20 @@ typedef void (DNSSD_API *DNSServiceNATPortMappingReply)
/* DNSServiceNATPortMappingCreate() Parameters:
*
- * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds then it
- * initializes the DNSServiceRef, returns kDNSServiceErr_NoError, and the nat
- * port mapping will last indefinitely until the client terminates the port
- * mapping request by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ * sdRef: A pointer to an uninitialized DNSServiceRef
+ * (or, if the kDNSServiceFlagsShareConnection flag is used,
+ * a copy of the shared connection reference that is to be used).
+ * If the call succeeds then it initializes (or updates) the DNSServiceRef,
+ * returns kDNSServiceErr_NoError, and the NAT port mapping
+ * will remain active indefinitely until the client terminates it
+ * by passing this DNSServiceRef to DNSServiceRefDeallocate()
+ * (or by closing the underlying shared connection, if used).
*
- * flags: Currently ignored, reserved for future use.
+ * flags: Possible values are:
+ * kDNSServiceFlagsShareConnection to use a shared connection.
*
- * interfaceIndex: The interface on which to create port mappings in a NAT gateway. Passing 0 causes
- * the port mapping request to be sent on the primary interface.
+ * interfaceIndex: The interface on which to create port mappings in a NAT gateway.
+ * Passing 0 causes the port mapping request to be sent on the primary interface.
*
* protocol: To request a port mapping, pass in kDNSServiceProtocol_UDP, or kDNSServiceProtocol_TCP,
* or (kDNSServiceProtocol_UDP | kDNSServiceProtocol_TCP) to map both.
@@ -2315,7 +2359,11 @@ typedef union _TXTRecordRef_t { char PrivateData[16]; char *ForceNaturalAlignmen
*
* If the buffer parameter is NULL, or the specified storage size is not
* large enough to hold a key subsequently added using TXTRecordSetValue(),
- * then additional memory will be added as needed using malloc().
+ * then additional memory will be added as needed using malloc(). Note that
+ * an existing TXT record buffer should not be passed to TXTRecordCreate
+ * to create a copy of another TXT Record. The correct way to copy TXTRecordRef
+ * is creating an empty TXTRecordRef with TXTRecordCreate() first, and using
+ * TXTRecordSetValue to set the same value.
*
* On some platforms, when memory is low, malloc() may fail. In this
* case, TXTRecordSetValue() will return kDNSServiceErr_NoMemory, and this
@@ -2613,7 +2661,7 @@ uint16_t DNSSD_API TXTRecordGetCount
* keyBufLen: The size of the string buffer being supplied.
*
* key: A string buffer used to store the key name.
- * On return, the buffer contains a null-terminated C string
+ * On return, the buffer contains a null-terminated C-string
* giving the key name. DNS-SD TXT keys are usually
* 9 characters or fewer. To hold the maximum possible
* key name, the buffer should be 256 bytes long.
@@ -2670,6 +2718,8 @@ DNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex
* DNSServiceSetDispatchQueue a second time to schedule the DNSServiceRef onto a different serial dispatch
* queue. Once scheduled onto a dispatch queue a DNSServiceRef will deliver events to that queue until
* the application no longer requires that operation and terminates it using DNSServiceRefDeallocate.
+ * Note that the call to DNSServiceRefDeallocate() must be done on the same queue originally passed
+ * as an argument to DNSServiceSetDispatchQueue().
*
* service: DNSServiceRef that was allocated and returned to the application, when the
* application calls one of the DNSService API.
diff --git a/usr/src/contrib/mDNSResponder/mDNSShared/dns_sd_internal.h b/usr/src/contrib/mDNSResponder/mDNSShared/dns_sd_internal.h
index 4be93e943b..a3755a1f61 100644
--- a/usr/src/contrib/mDNSResponder/mDNSShared/dns_sd_internal.h
+++ b/usr/src/contrib/mDNSResponder/mDNSShared/dns_sd_internal.h
@@ -1,15 +1,28 @@
-/* -*- Mode: C; tab-width: 4 -*-
+/*
+ * Copyright (c) 2016-2020 Apple Inc. All rights reserved.
*
- * Copyright (c) 2016 Apple Inc. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
#ifndef _DNS_SD_INTERNAL_H
#define _DNS_SD_INTERNAL_H
-#if !APPLE_OSX_mDNSResponder
-#define DNSSD_NO_CREATE_DELEGATE_CONNECTION 1
+// The mDNSResponder daemon doesn't call the private DNS-SD API.
+
+#if !defined(DNS_SD_EXCLUDE_PRIVATE_API)
+ #define DNS_SD_EXCLUDE_PRIVATE_API 1
#endif
#include "dns_sd_private.h"
-#endif
+#endif // _DNS_SD_INTERNAL_H
diff --git a/usr/src/contrib/mDNSResponder/mDNSShared/dns_sd_private.h b/usr/src/contrib/mDNSResponder/mDNSShared/dns_sd_private.h
index 2d42973361..1c4baabfb2 100644
--- a/usr/src/contrib/mDNSResponder/mDNSShared/dns_sd_private.h
+++ b/usr/src/contrib/mDNSResponder/mDNSShared/dns_sd_private.h
@@ -1,6 +1,17 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2015-2018 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2015-2020 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
#ifndef _DNS_SD_PRIVATE_H
@@ -8,9 +19,23 @@
#include <dns_sd.h>
-// Private flags (kDNSServiceFlagsPrivateOne, kDNSServiceFlagsPrivateTwo, kDNSServiceFlagsPrivateThree, kDNSServiceFlagsPrivateFour) from dns_sd.h
+#if !defined(DNS_SD_EXCLUDE_PRIVATE_API)
+ #if defined(__APPLE__)
+ #define DNS_SD_EXCLUDE_PRIVATE_API 0
+ #else
+ #define DNS_SD_EXCLUDE_PRIVATE_API 1
+ #endif
+#endif
+
+// Private flags (kDNSServiceFlagsPrivateOne, kDNSServiceFlagsPrivateTwo, kDNSServiceFlagsPrivateThree, kDNSServiceFlagsPrivateFour, kDNSServiceFlagsPrivateFive) from dns_sd.h
enum
{
+ kDNSServiceFlagsDenyConstrained = 0x2000,
+ /*
+ * This flag is meaningful only for Unicast DNS queries. When set, the daemon will restrict
+ * DNS resolutions on interfaces defined as constrained for that request.
+ */
+
kDNSServiceFlagsDenyCellular = 0x8000000,
/*
* This flag is meaningful only for Unicast DNS queries. When set, the daemon will restrict
@@ -36,8 +61,7 @@ enum
*/
};
-
-#if !DNSSD_NO_CREATE_DELEGATE_CONNECTION
+#if !DNS_SD_EXCLUDE_PRIVATE_API
/* DNSServiceCreateDelegateConnection()
*
* Parameters:
@@ -61,7 +85,6 @@ enum
*/
DNSSD_EXPORT
DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *sdRef, int32_t pid, uuid_t uuid);
-#endif
// Map the source port of the local UDP socket that was opened for sending the DNS query
// to the process ID of the application that triggered the DNS resolution.
@@ -89,7 +112,50 @@ DNSServiceErrorType DNSSD_API DNSServiceGetPID
DNSSD_EXPORT
DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain);
+SPI_AVAILABLE(macos(10.15.4), ios(13.2.2), watchos(6.2), tvos(13.2))
+DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive_sockaddr
+(
+ DNSServiceRef * sdRef,
+ DNSServiceFlags flags,
+ const struct sockaddr * localAddr,
+ const struct sockaddr * remoteAddr,
+ unsigned int timeout,
+ DNSServiceSleepKeepaliveReply callBack,
+ void * context
+);
+
+/*!
+ * @brief
+ * Sets the default DNS resolver settings for the caller's process.
+ *
+ * @param plist_data_ptr
+ * Pointer to an nw_resolver_config's binary property list data.
+ *
+ * @param plist_data_len
+ * Byte-length of the binary property list data. Ignored if plist_data_ptr is NULL.
+ *
+ * @param require_encryption
+ * Pass true if the process requires that DNS queries use an encrypted DNS service, such as DNS over HTTPS.
+ *
+ * @result
+ * This function returns kDNSServiceErr_NoError on success, kDNSServiceErr_Invalid if plist_data_len
+ * exceeds 32,768, and kDNSServiceErr_NoMemory if it fails to allocate memory.
+ *
+ * @discussion
+ * These settings only apply to the calling process's DNSServiceGetAddrInfo and DNSServiceQueryRecord
+ * requests. This function exists for code that may still use the legacy DNS-SD API for resolving
+ * hostnames, i.e., it implements the functionality of dnssd_getaddrinfo_set_need_encrypted_query(), but at
+ * a process-wide level of granularity.
+ *
+ * Due to underlying IPC limitations, there's currently a 32 KB limit on the size of the binary property
+ * list data.
+ */
+SPI_AVAILABLE(macos(10.16), ios(14.0), watchos(7.0), tvos(14.0))
+DNSServiceErrorType DNSSD_API DNSServiceSetResolverDefaults(const void *plist_data_ptr, size_t plist_data_len,
+ bool require_encryption);
+#endif // !DNS_SD_EXCLUDE_PRIVATE_API
+
#define kDNSServiceCompPrivateDNS "PrivateDNS"
#define kDNSServiceCompMulticastDNS "MulticastDNS"
-#endif
+#endif // _DNS_SD_PRIVATE_H
diff --git a/usr/src/contrib/mDNSResponder/mDNSShared/dnssd_clientstub.c b/usr/src/contrib/mDNSResponder/mDNSShared/dnssd_clientstub.c
index 189c9361fa..58b5a460e2 100644
--- a/usr/src/contrib/mDNSResponder/mDNSShared/dnssd_clientstub.c
+++ b/usr/src/contrib/mDNSResponder/mDNSShared/dnssd_clientstub.c
@@ -1,6 +1,6 @@
/* -*- Mode: C; tab-width: 4 -*-
*
- * Copyright (c) 2003-2015 Apple Inc. All rights reserved.
+ * Copyright (c) 2003-2020 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -36,7 +36,14 @@
#include <mach-o/dyld.h>
#include <uuid/uuid.h>
#include <TargetConditionals.h>
-#include "dns_sd_internal.h"
+#include "dns_sd_private.h"
+#include "dnssd_clientstub_apple.h"
+#include <CoreUtils/CommonServices.h>
+#if !defined(__i386__)
+#define CHECK_BUNDLE_VERSION 1
+#else
+#define CHECK_BUNDLE_VERSION 0
+#endif
#endif
#if defined(_WIN32)
@@ -81,7 +88,7 @@ static void syslog( int priority, const char * message, ...)
}
#else
- #include <sys/fcntl.h> // For O_RDWR etc.
+ #include <fcntl.h> // For O_RDWR etc.
#include <sys/time.h>
#include <sys/socket.h>
#include <syslog.h>
@@ -91,9 +98,16 @@ static void syslog( int priority, const char * message, ...)
#endif
+#if CHECK_BUNDLE_VERSION
+#include "bundle_utilities.h"
+#include <os/feature_private.h>
+#endif
+
+#if defined(_WIN32)
// <rdar://problem/4096913> Specifies how many times we'll try and connect to the server.
#define DNSSD_CLIENT_MAXTRIES 4
+#endif // _WIN32
// Uncomment the line below to use the old error return mechanism of creating a temporary named socket (e.g. in /var/tmp)
//#define USE_NAMED_ERROR_RETURN_SOCKET 1
@@ -173,6 +187,19 @@ struct _DNSRecordRef_t
DNSServiceOp *sdr;
};
+#if CHECK_BUNDLE_VERSION
+static bool _should_return_noauth_error(void)
+{
+ static dispatch_once_t s_once = 0;
+ static bool s_should = false;
+ dispatch_once(&s_once,
+ ^{
+ s_should = bundle_sdk_is_ios14_or_later();
+ });
+ return s_should;
+}
+#endif
+
#if !defined(USE_TCP_LOOPBACK)
static void SetUDSPath(struct sockaddr_un *saddr, const char *path)
{
@@ -186,11 +213,13 @@ static void SetUDSPath(struct sockaddr_un *saddr, const char *path)
}
#endif
+enum { write_all_success = 0, write_all_fail = -1, write_all_defunct = -2 };
+
// Write len bytes. Return 0 on success, -1 on error
static int write_all(dnssd_sock_t sd, char *buf, size_t len)
{
// Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
- //if (send(sd, buf, len, MSG_WAITALL) != len) return -1;
+ //if (send(sd, buf, len, MSG_WAITALL) != len) return write_all_fail;
while (len)
{
ssize_t num_written = send(sd, buf, (long)len, 0);
@@ -211,21 +240,22 @@ static int write_all(dnssd_sock_t sd, char *buf, size_t len)
(num_written < 0) ? dnssd_strerror(dnssd_errno) : "");
else
syslog(LOG_INFO, "dnssd_clientstub write_all(%d) DEFUNCT", sd);
+ return defunct ? write_all_defunct : write_all_fail;
#else
syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %ld/%ld %d %s", sd,
(long)num_written, (long)len,
(num_written < 0) ? dnssd_errno : 0,
(num_written < 0) ? dnssd_strerror(dnssd_errno) : "");
+ return write_all_fail;
#endif
- return -1;
}
buf += num_written;
len -= num_written;
}
- return 0;
+ return write_all_success;
}
-enum { read_all_success = 0, read_all_fail = -1, read_all_wouldblock = -2 };
+enum { read_all_success = 0, read_all_fail = -1, read_all_wouldblock = -2, read_all_defunct = -3 };
// Read len bytes. Return 0 on success, read_all_fail on error, or read_all_wouldblock for
static int read_all(dnssd_sock_t sd, char *buf, int len)
@@ -273,7 +303,7 @@ static int read_all(dnssd_sock_t sd, char *buf, int len)
(num_read < 0) ? dnssd_strerror(dnssd_errno) : "");
else if (defunct)
syslog(LOG_INFO, "dnssd_clientstub read_all(%d) DEFUNCT", sd);
- return (num_read < 0 && dnssd_errno == dnssd_EWOULDBLOCK) ? read_all_wouldblock : read_all_fail;
+ return (num_read < 0 && dnssd_errno == dnssd_EWOULDBLOCK) ? read_all_wouldblock : (defunct ? read_all_defunct : read_all_fail);
}
buf += num_read;
len -= num_read;
@@ -295,6 +325,7 @@ static int more_bytes(dnssd_sock_t sd)
FD_SET(sd, fs);
ret = select((int)sd+1, fs, (fd_set*)NULL, (fd_set*)NULL, &tv);
#else
+ // This whole thing would probably be better done using kevent() instead of select()
if (sd < FD_SETSIZE)
{
fs = &readfds;
@@ -333,6 +364,10 @@ static int set_waitlimit(dnssd_sock_t sock, int timeout)
{
int gDaemonErr = kDNSServiceErr_NoError;
+ // The comment below is wrong. The select() routine does not cause stack corruption.
+ // The use of FD_SET out of range for the bitmap is what causes stack corruption.
+ // For how to do this correctly, see the example using calloc() in more_bytes() above.
+ // Even better, both should be changed to use kevent() instead of select().
// To prevent stack corruption since select does not work with timeout if fds > FD_SETSIZE(1024)
if (!gDaemonErr && sock < FD_SETSIZE)
{
@@ -431,9 +466,6 @@ static void FreeDNSServiceOp(DNSServiceOp *x)
// then sockfd could legitimately contain a failing value (e.g. dnssd_InvalidSocket)
if ((x->sockfd ^ x->validator) != ValidatorBits)
{
- static DNSServiceOp *op_were_not_going_to_free_but_we_need_to_fool_the_analyzer;
- syslog(LOG_WARNING, "dnssd_clientstub attempt to dispose invalid DNSServiceRef %p %08X %08X", x, x->sockfd, x->validator);
- op_were_not_going_to_free_but_we_need_to_fool_the_analyzer = x;
}
else
{
@@ -469,7 +501,9 @@ static void FreeDNSServiceOp(DNSServiceOp *x)
// Return a connected service ref (deallocate with DNSServiceRefDeallocate)
static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags flags, uint32_t op, ProcessReplyFn ProcessReply, void *AppCallback, void *AppContext)
{
+ #if defined(_WIN32)
int NumTries = 0;
+ #endif // _WIN32
dnssd_sockaddr_t saddr;
DNSServiceOp *sdr;
@@ -534,7 +568,7 @@ static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags f
sdr->disp_queue = NULL;
#endif
sdr->kacontext = NULL;
-
+
if (flags & kDNSServiceFlagsShareConnection)
{
DNSServiceOp **p = &(*ref)->next; // Append ourselves to end of primary's list
@@ -574,6 +608,22 @@ static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags f
FreeDNSServiceOp(sdr);
return kDNSServiceErr_NoMemory;
}
+#if !defined(_WIN32)
+ int fcntl_flags = fcntl(sdr->sockfd, F_GETFD);
+ if (fcntl_flags != -1)
+ {
+ fcntl_flags |= FD_CLOEXEC;
+ int ret = fcntl(sdr->sockfd, F_SETFD, fcntl_flags);
+ if (ret == -1)
+ syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: Failed to set FD_CLOEXEC on socket %d %s",
+ dnssd_errno, dnssd_strerror(dnssd_errno));
+ }
+ else
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: Failed to get the file descriptor flags of socket %d %s",
+ dnssd_errno, dnssd_strerror(dnssd_errno));
+ }
+#endif // !defined(_WIN32)
#ifdef SO_NOSIGPIPE
// Some environments (e.g. OS X) support turning off SIGPIPE for a socket
if (setsockopt(sdr->sockfd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0)
@@ -595,11 +645,13 @@ static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags f
#endif
#endif
+ #if defined(_WIN32)
while (1)
{
int err = connect(sdr->sockfd, (struct sockaddr *) &saddr, sizeof(saddr));
if (!err)
break; // If we succeeded, return sdr
+
// If we failed, then it may be because the daemon is still launching.
// This can happen for processes that launch early in the boot process, while the
// daemon is still coming up. Rather than fail here, we wait 1 sec and try again.
@@ -621,7 +673,19 @@ static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags f
return kDNSServiceErr_ServiceNotRunning;
}
}
- //printf("ConnectToServer opened socket %d\n", sdr->sockfd);
+ #else
+ int err = connect(sdr->sockfd, (struct sockaddr *) &saddr, sizeof(saddr));
+ if (err)
+ {
+ #if !defined(USE_TCP_LOOPBACK)
+ syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: connect() failed path:%s Socket:%d Err:%d Errno:%d %s",
+ uds_serverpath, sdr->sockfd, err, dnssd_errno, dnssd_strerror(dnssd_errno));
+ #endif
+ dnssd_close(sdr->sockfd);
+ FreeDNSServiceOp(sdr);
+ return kDNSServiceErr_ServiceNotRunning;
+ }
+ #endif
}
*ref = sdr;
@@ -637,6 +701,7 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
dnssd_sock_t listenfd = dnssd_InvalidSocket, errsd = dnssd_InvalidSocket;
DNSServiceErrorType err = kDNSServiceErr_Unknown; // Default for the "goto cleanup" cases
int MakeSeparateReturnSocket;
+ int ioresult;
#if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET)
char *data;
#endif
@@ -736,7 +801,7 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
{
int defunct = 1;
if (setsockopt(errsd, SOL_SOCKET, SO_DEFUNCTOK, &defunct, sizeof(defunct)) < 0)
- syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_DEFUNCTOK failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
+ syslog(LOG_WARNING, "dnssd_clientstub deliver_request: SO_DEFUNCTOK failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
}
#endif
}
@@ -764,18 +829,25 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
for (i=0; i<datalen + sizeof(ipc_msg_hdr); i++)
{
syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %d", i);
- if (write_all(sdr->sockfd, ((char *)hdr)+i, 1) < 0)
- { syslog(LOG_WARNING, "write_all (byte %u) failed", i); goto cleanup; }
+ ioresult = write_all(sdr->sockfd, ((char *)hdr)+i, 1);
+ if (ioresult < write_all_success)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub deliver_request write_all (byte %u) failed", i);
+ err = (ioresult == write_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning;
+ goto cleanup;
+ }
usleep(10000);
}
#else
- if (write_all(sdr->sockfd, (char *)hdr, datalen + sizeof(ipc_msg_hdr)) < 0)
+ ioresult = write_all(sdr->sockfd, (char *)hdr, datalen + sizeof(ipc_msg_hdr));
+ if (ioresult < write_all_success)
{
// write_all already prints an error message if there is an error writing to
// the socket except for DEFUNCT. Logging here is unnecessary and also wrong
// in the case of DEFUNCT sockets
syslog(LOG_INFO, "dnssd_clientstub deliver_request ERROR: write_all(%d, %lu bytes) failed",
sdr->sockfd, (unsigned long)(datalen + sizeof(ipc_msg_hdr)));
+ err = (ioresult == write_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning;
goto cleanup;
}
#endif
@@ -818,9 +890,9 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
{
snprintf(p, sizeof(p), "/dev/bpf%d", i);
listenfd = open(p, O_RDWR, 0);
- //if (dnssd_SocketValid(listenfd)) syslog(LOG_WARNING, "Sending fd %d for %s", listenfd, p);
+ //if (dnssd_SocketValid(listenfd)) syslog(LOG_WARNING, "dnssd_clientstub deliver_request Sending fd %d for %s", listenfd, p);
if (!dnssd_SocketValid(listenfd) && dnssd_errno != EBUSY)
- syslog(LOG_WARNING, "Error opening %s %d (%s)", p, dnssd_errno, dnssd_strerror(dnssd_errno));
+ syslog(LOG_WARNING, "dnssd_clientstub deliver_request Error opening %s %d (%s)", p, dnssd_errno, dnssd_strerror(dnssd_errno));
if (dnssd_SocketValid(listenfd) || dnssd_errno != EBUSY) break;
}
}
@@ -839,7 +911,7 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
#endif
#if DEBUG_64BIT_SCM_RIGHTS
- syslog(LOG_WARNING, "dnssd_clientstub sendmsg read sd=%d write sd=%d %ld %ld %ld/%ld/%ld/%ld",
+ syslog(LOG_WARNING, "dnssd_clientstub deliver_request sendmsg read sd=%d write sd=%d %ld %ld %ld/%ld/%ld/%ld",
errsd, listenfd, sizeof(dnssd_sock_t), sizeof(void*),
sizeof(struct cmsghdr) + sizeof(dnssd_sock_t),
CMSG_LEN(sizeof(dnssd_sock_t)), (long)CMSG_SPACE(sizeof(dnssd_sock_t)),
@@ -855,7 +927,7 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
}
#if DEBUG_64BIT_SCM_RIGHTS
- syslog(LOG_WARNING, "dnssd_clientstub sendmsg read sd=%d write sd=%d okay", errsd, listenfd);
+ syslog(LOG_WARNING, "dnssd_clientstub deliver_request sendmsg read sd=%d write sd=%d okay", errsd, listenfd);
#endif // DEBUG_64BIT_SCM_RIGHTS
#endif
@@ -875,8 +947,9 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
err = kDNSServiceErr_NoError;
else if ((err = set_waitlimit(errsd, DNSSD_CLIENT_TIMEOUT)) == kDNSServiceErr_NoError)
{
- if (read_all(errsd, (char*)&err, (int)sizeof(err)) < 0)
- err = kDNSServiceErr_ServiceNotRunning; // On failure read_all will have written a message to syslog for us
+ ioresult = read_all(errsd, (char*)&err, (int)sizeof(err));
+ if (ioresult < read_all_success)
+ err = (ioresult == read_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning; // On failure read_all will have written a message to syslog for us
else
err = ntohl(err);
}
@@ -964,7 +1037,7 @@ static void CallbackWithError(DNSServiceRef sdRef, DNSServiceErrorType error)
if (rec->AppCallback) ((DNSServiceRegisterRecordReply)rec->AppCallback)(sdr, 0, 0, error, rec->AppContext);
// The Callback can call DNSServiceRefDeallocate which in turn frees sdr and all the records.
// Detect that and return early
- if (!morebytes) {syslog(LOG_WARNING, "dnssdclientstub:Record: CallbackwithError morebytes zero"); return;}
+ if (!morebytes) { syslog(LOG_WARNING, "dnssd_clientstub:Record: CallbackwithError morebytes zero"); return; }
rec = recnext;
}
break;
@@ -982,7 +1055,7 @@ static void CallbackWithError(DNSServiceRef sdRef, DNSServiceErrorType error)
//
// If DNSServiceRefDeallocate was not called in the callback, then set moreptr to NULL so that
// we don't access the stack variable after we return from this function.
- if (!morebytes) {syslog(LOG_WARNING, "dnssdclientstub:sdRef: CallbackwithError morebytes zero sdr %p", sdr); return;}
+ if (!morebytes) { syslog(LOG_WARNING, "dnssd_clientstub:sdRef: CallbackwithError morebytes zero sdr %p", sdr); return; }
else {sdr->moreptr = NULL;}
sdr = sdrNext;
}
@@ -994,6 +1067,8 @@ static void CallbackWithError(DNSServiceRef sdRef, DNSServiceErrorType error)
DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef)
{
int morebytes = 0;
+ int ioresult;
+ DNSServiceErrorType error;
if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
@@ -1026,9 +1101,11 @@ DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef)
// where a non-blocking socket is told there is data, but it was a false positive.
// On error, read_all will write a message to syslog for us, so don't need to duplicate that here
// Note: If we want to properly support using non-blocking sockets in the future
- int result = read_all(sdRef->sockfd, (void *)&cbh.ipc_hdr, sizeof(cbh.ipc_hdr));
- if (result == read_all_fail)
+ ioresult = read_all(sdRef->sockfd, (void *)&cbh.ipc_hdr, sizeof(cbh.ipc_hdr));
+ if (ioresult == read_all_fail || ioresult == read_all_defunct)
{
+ error = (ioresult == read_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning;
+
// Set the ProcessReply to NULL before callback as the sdRef can get deallocated
// in the callback.
sdRef->ProcessReply = NULL;
@@ -1043,13 +1120,13 @@ DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef)
dispatch_source_cancel(sdRef->disp_source);
dispatch_release(sdRef->disp_source);
sdRef->disp_source = NULL;
- CallbackWithError(sdRef, kDNSServiceErr_ServiceNotRunning);
+ CallbackWithError(sdRef, error);
}
#endif
// Don't touch sdRef anymore as it might have been deallocated
- return kDNSServiceErr_ServiceNotRunning;
+ return error;
}
- else if (result == read_all_wouldblock)
+ else if (ioresult == read_all_wouldblock)
{
if (morebytes && sdRef->logcounter < 100)
{
@@ -1069,8 +1146,11 @@ DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef)
data = malloc(cbh.ipc_hdr.datalen);
if (!data) return kDNSServiceErr_NoMemory;
- if (read_all(sdRef->sockfd, data, cbh.ipc_hdr.datalen) < 0) // On error, read_all will write a message to syslog for us
+ ioresult = read_all(sdRef->sockfd, data, cbh.ipc_hdr.datalen);
+ if (ioresult < read_all_success) // On error, read_all will write a message to syslog for us
{
+ error = (ioresult == read_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning;
+
// Set the ProcessReply to NULL before callback as the sdRef can get deallocated
// in the callback.
sdRef->ProcessReply = NULL;
@@ -1083,12 +1163,12 @@ DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef)
dispatch_source_cancel(sdRef->disp_source);
dispatch_release(sdRef->disp_source);
sdRef->disp_source = NULL;
- CallbackWithError(sdRef, kDNSServiceErr_ServiceNotRunning);
+ CallbackWithError(sdRef, error);
}
#endif
// Don't touch sdRef anymore as it might have been deallocated
free(data);
- return kDNSServiceErr_ServiceNotRunning;
+ return error;
}
else
{
@@ -1207,6 +1287,7 @@ DNSServiceErrorType DNSSD_API DNSServiceGetProperty(const char *property, void *
ipc_msg_hdr *hdr;
DNSServiceOp *tmp;
uint32_t actualsize;
+ int ioresult;
if (!property || !result || !size)
return kDNSServiceErr_BadParam;
@@ -1222,12 +1303,14 @@ DNSServiceErrorType DNSSD_API DNSServiceGetProperty(const char *property, void *
err = deliver_request(hdr, tmp); // Will free hdr for us
if (err) { DNSServiceRefDeallocate(tmp); return err; }
- if (read_all(tmp->sockfd, (char*)&actualsize, (int)sizeof(actualsize)) < 0)
- { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; }
+ ioresult = read_all(tmp->sockfd, (char*)&actualsize, (int)sizeof(actualsize));
+ if (ioresult < read_all_success)
+ { DNSServiceRefDeallocate(tmp); return (ioresult == read_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning; }
actualsize = ntohl(actualsize);
- if (read_all(tmp->sockfd, (char*)result, actualsize < *size ? actualsize : *size) < 0)
- { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; }
+ ioresult = read_all(tmp->sockfd, (char*)result, actualsize < *size ? actualsize : *size);
+ if (ioresult < read_all_success)
+ { DNSServiceRefDeallocate(tmp); return (ioresult == read_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning; }
DNSServiceRefDeallocate(tmp);
// Swap version result back to local process byte order
@@ -1244,6 +1327,7 @@ DNSServiceErrorType DNSSD_API DNSServiceGetPID(const uint16_t srcport, int32_t *
ipc_msg_hdr *hdr;
DNSServiceOp *tmp = NULL;
size_t len = sizeof(int32_t);
+ int ioresult;
DNSServiceErrorType err = ConnectToServer(&tmp, 0, getpid_request, NULL, NULL, NULL);
if (err) return err;
@@ -1255,8 +1339,9 @@ DNSServiceErrorType DNSSD_API DNSServiceGetPID(const uint16_t srcport, int32_t *
err = deliver_request(hdr, tmp); // Will free hdr for us
if (err) { DNSServiceRefDeallocate(tmp); return err; }
- if (read_all(tmp->sockfd, (char*)pid, sizeof(int32_t)) < 0)
- { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; }
+ ioresult = read_all(tmp->sockfd, (char*)pid, sizeof(int32_t));
+ if (ioresult < read_all_success)
+ { DNSServiceRefDeallocate(tmp); return (ioresult == read_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning; }
DNSServiceRefDeallocate(tmp);
return kDNSServiceErr_NoError;
@@ -1287,7 +1372,7 @@ fail:
syslog(LOG_WARNING, "dnssd_clientstub handle_resolve_response: error reading result from daemon");
}
-#if TARGET_OS_EMBEDDED
+#if TARGET_OS_IPHONE
static int32_t libSystemVersion = 0;
@@ -1305,7 +1390,7 @@ static int includeP2PWithIndexAny()
return 0;
}
-#else // TARGET_OS_EMBEDDED
+#else // TARGET_OS_IPHONE
// always return false for non iOS platforms
static int includeP2PWithIndexAny()
@@ -1313,7 +1398,7 @@ static int includeP2PWithIndexAny()
return 0;
}
-#endif // TARGET_OS_EMBEDDED
+#endif // TARGET_OS_IPHONE
DNSServiceErrorType DNSSD_API DNSServiceResolve
(
@@ -1368,12 +1453,24 @@ DNSServiceErrorType DNSSD_API DNSServiceResolve
put_string(domain, &ptr);
err = deliver_request(hdr, *sdRef); // Will free hdr for us
+#if CHECK_BUNDLE_VERSION
+ if (err == kDNSServiceErr_NoAuth && !_should_return_noauth_error())
+ {
+ err = kDNSServiceErr_NoError;
+ }
+#endif
if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
return err;
}
static void handle_query_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
{
+#if CHECK_BUNDLE_VERSION
+ if (cbh->cb_err == kDNSServiceErr_PolicyDenied && !_should_return_noauth_error())
+ {
+ return;
+ }
+#endif
uint32_t ttl;
char name[kDNSServiceMaxDomainName];
uint16_t rrtype, rrclass, rdlen;
@@ -1391,6 +1488,37 @@ static void handle_query_response(DNSServiceOp *const sdr, const CallbackHeader
// MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
}
+#if APPLE_OSX_mDNSResponder
+static size_t get_required_length_for_defaults(const xpc_object_t defaults)
+{
+ size_t required_len = 0;
+ size_t plist_data_len = 0;
+ // Add length for IPC_TLV_TYPE_RESOLVER_CONFIG_PLIST_DATA.
+ if (xpc_dictionary_get_data(defaults, kDNSServiceDefaultsKey_ResolverConfigPListData, &plist_data_len))
+ {
+ required_len += get_required_tlv16_length(plist_data_len);
+ }
+ // Add length for IPC_TLV_TYPE_REQUIRE_PRIVACY.
+ required_len += get_required_tlv16_length(sizeof(uint8_t));
+ return required_len;
+}
+
+static void put_tlvs_for_defaults(const xpc_object_t defaults, ipc_msg_hdr *const hdr, char **ptr)
+{
+ uint8_t require_privacy;
+ size_t plist_data_len = 0;
+ const uint8_t *const plist_data_ptr = xpc_dictionary_get_data(defaults,
+ kDNSServiceDefaultsKey_ResolverConfigPListData, &plist_data_len);
+ if (plist_data_ptr)
+ {
+ put_tlv16(IPC_TLV_TYPE_RESOLVER_CONFIG_PLIST_DATA, (uint16_t)plist_data_len, plist_data_ptr, ptr);
+ }
+ require_privacy = xpc_dictionary_get_bool(defaults, kDNSServiceDefaultsKey_RequirePrivacy) ? 1 : 0;
+ put_tlv16(IPC_TLV_TYPE_REQUIRE_PRIVACY, sizeof(require_privacy), &require_privacy, ptr);
+ hdr->ipc_flags |= IPC_FLAGS_TRAILING_TLVS;
+}
+#endif
+
DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
(
DNSServiceRef *sdRef,
@@ -1407,7 +1535,9 @@ DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
size_t len;
ipc_msg_hdr *hdr;
DNSServiceErrorType err;
-
+#if APPLE_OSX_mDNSResponder
+ xpc_object_t defaults;
+#endif
// NULL name handled below.
if (!sdRef || !callBack) return kDNSServiceErr_BadParam;
@@ -1424,23 +1554,54 @@ DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
len += sizeof(uint32_t); // interfaceIndex
len += strlen(name) + 1;
len += 2 * sizeof(uint16_t); // rrtype, rrclass
-
+#if APPLE_OSX_mDNSResponder
+ defaults = DNSServiceGetRetainedResolverDefaults();
+ if (defaults)
+ {
+ len += get_required_length_for_defaults(defaults);
+ }
+#endif
hdr = create_hdr(query_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
- if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
-
+ if (!hdr)
+ {
+ DNSServiceRefDeallocate(*sdRef);
+ *sdRef = NULL;
+#if APPLE_OSX_mDNSResponder
+ xpc_forget(&defaults);
+#endif
+ return kDNSServiceErr_NoMemory;
+ }
put_flags(flags, &ptr);
put_uint32(interfaceIndex, &ptr);
put_string(name, &ptr);
put_uint16(rrtype, &ptr);
put_uint16(rrclass, &ptr);
-
+#if APPLE_OSX_mDNSResponder
+ if (defaults)
+ {
+ put_tlvs_for_defaults(defaults, hdr, &ptr);
+ xpc_forget(&defaults);
+ }
+#endif
err = deliver_request(hdr, *sdRef); // Will free hdr for us
+#if CHECK_BUNDLE_VERSION
+ if (err == kDNSServiceErr_NoAuth && !_should_return_noauth_error())
+ {
+ err = kDNSServiceErr_NoError;
+ }
+#endif
if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
return err;
}
static void handle_addrinfo_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
{
+#if CHECK_BUNDLE_VERSION
+ if (cbh->cb_err == kDNSServiceErr_PolicyDenied && !_should_return_noauth_error())
+ {
+ return;
+ }
+#endif
char hostname[kDNSServiceMaxDomainName];
uint16_t rrtype, rrclass, rdlen;
const char *rdata;
@@ -1490,17 +1651,12 @@ static void handle_addrinfo_response(DNSServiceOp *const sdr, const CallbackHead
if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr)) sa6.sin6_scope_id = cbh->cb_interface;
}
}
- // Validation results are always delivered separately from the actual results of the
- // DNSServiceGetAddrInfo. Set the "addr" to NULL as per the documentation.
- //
- // Note: If we deliver validation results along with the "addr" in the future, we need
- // a way to differentiate the negative response from validation-only response as both
- // has zero address.
- if (!(cbh->cb_flags & kDNSServiceFlagsValidate))
- ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, hostname, sa, ttl, sdr->AppContext);
- else
- ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, hostname, NULL, 0, sdr->AppContext);
- // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+
+ ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, hostname, sa, ttl, sdr->AppContext);
+ }
+ else if (cbh->cb_err == kDNSServiceErr_PolicyDenied)
+ {
+ ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, hostname, NULL, ttl, sdr->AppContext);
}
}
@@ -1519,6 +1675,9 @@ DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo
size_t len;
ipc_msg_hdr *hdr;
DNSServiceErrorType err;
+#if APPLE_OSX_mDNSResponder
+ xpc_object_t defaults;
+#endif
if (!sdRef || !hostname || !callBack) return kDNSServiceErr_BadParam;
@@ -1533,22 +1692,53 @@ DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo
len += sizeof(uint32_t); // interfaceIndex
len += sizeof(uint32_t); // protocol
len += strlen(hostname) + 1;
-
+#if APPLE_OSX_mDNSResponder
+ defaults = DNSServiceGetRetainedResolverDefaults();
+ if (defaults)
+ {
+ len += get_required_length_for_defaults(defaults);
+ }
+#endif
hdr = create_hdr(addrinfo_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
- if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
-
+ if (!hdr)
+ {
+ DNSServiceRefDeallocate(*sdRef);
+ *sdRef = NULL;
+#if APPLE_OSX_mDNSResponder
+ xpc_forget(&defaults);
+#endif
+ return kDNSServiceErr_NoMemory;
+ }
put_flags(flags, &ptr);
put_uint32(interfaceIndex, &ptr);
put_uint32(protocol, &ptr);
put_string(hostname, &ptr);
-
+#if APPLE_OSX_mDNSResponder
+ if (defaults)
+ {
+ put_tlvs_for_defaults(defaults, hdr, &ptr);
+ xpc_forget(&defaults);
+ }
+#endif
err = deliver_request(hdr, *sdRef); // Will free hdr for us
+#if CHECK_BUNDLE_VERSION
+ if (err == kDNSServiceErr_NoAuth && !_should_return_noauth_error())
+ {
+ err = kDNSServiceErr_NoError;
+ }
+#endif
if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
return err;
}
static void handle_browse_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
{
+#if CHECK_BUNDLE_VERSION
+ if (cbh->cb_err == kDNSServiceErr_PolicyDenied && !_should_return_noauth_error())
+ {
+ return;
+ }
+#endif
char replyName[256], replyType[kDNSServiceMaxDomainName], replyDomain[kDNSServiceMaxDomainName];
get_string(&data, end, replyName, 256);
get_string(&data, end, replyType, kDNSServiceMaxDomainName);
@@ -1598,6 +1788,12 @@ DNSServiceErrorType DNSSD_API DNSServiceBrowse
put_string(domain, &ptr);
err = deliver_request(hdr, *sdRef); // Will free hdr for us
+#if CHECK_BUNDLE_VERSION
+ if (err == kDNSServiceErr_NoAuth && !_should_return_noauth_error())
+ {
+ err = kDNSServiceErr_NoError;
+ }
+#endif
if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
return err;
}
@@ -1628,6 +1824,12 @@ DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags
static void handle_regservice_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
{
+#if CHECK_BUNDLE_VERSION
+ if (cbh->cb_err == kDNSServiceErr_PolicyDenied && !_should_return_noauth_error())
+ {
+ return;
+ }
+#endif
char name[256], regtype[kDNSServiceMaxDomainName], domain[kDNSServiceMaxDomainName];
get_string(&data, end, name, 256);
get_string(&data, end, regtype, kDNSServiceMaxDomainName);
@@ -1696,6 +1898,12 @@ DNSServiceErrorType DNSSD_API DNSServiceRegister
put_rdata(txtLen, txtRecord, &ptr);
err = deliver_request(hdr, *sdRef); // Will free hdr for us
+#if CHECK_BUNDLE_VERSION
+ if (err == kDNSServiceErr_NoAuth && !_should_return_noauth_error())
+ {
+ err = kDNSServiceErr_NoError;
+ }
+#endif
if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
return err;
}
@@ -1769,6 +1977,12 @@ static void ConnectionResponse(DNSServiceOp *const sdr, const CallbackHeader *co
}
else
{
+#if CHECK_BUNDLE_VERSION
+ if (cbh->cb_err == kDNSServiceErr_PolicyDenied && !_should_return_noauth_error())
+ {
+ return;
+ }
+#endif
DNSRecordRef rec;
for (rec = sdr->rec; rec; rec = rec->recnext)
{
@@ -1779,12 +1993,12 @@ static void ConnectionResponse(DNSServiceOp *const sdr, const CallbackHeader *co
// error if the record is not found.
if (!rec)
{
- syslog(LOG_INFO, "ConnectionResponse: Record not found");
+ syslog(LOG_INFO, "dnssd_clientstub ConnectionResponse: Record not found");
return;
}
if (rec->sdr != sdr)
{
- syslog(LOG_WARNING, "ConnectionResponse: Record sdr mismatch: rec %p sdr %p", rec->sdr, sdr);
+ syslog(LOG_WARNING, "dnssd_clientstub ConnectionResponse: Record sdr mismatch: rec %p sdr %p", rec->sdr, sdr);
return;
}
@@ -1820,7 +2034,7 @@ DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef)
return err;
}
-#if APPLE_OSX_mDNSResponder && !TARGET_IPHONE_SIMULATOR
+#if APPLE_OSX_mDNSResponder && !TARGET_OS_SIMULATOR
DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *sdRef, int32_t pid, uuid_t uuid)
{
char *ptr;
@@ -1849,9 +2063,9 @@ DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *
}
if (pid && setsockopt((*sdRef)->sockfd, SOL_SOCKET, SO_DELEGATED, &pid, sizeof(pid)) == -1)
- {
- syslog(LOG_WARNING, "dnssdclientstub: Could not setsockopt() for PID[%d], no entitlements or process(pid) invalid errno:%d (%s)", pid, errno, strerror(errno));
- // Free the hdr in case we return before calling deliver_request()
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceCreateDelegateConnection: Could not setsockopt() for PID[%d], no entitlements or process(pid) invalid errno:%d (%s)", pid, errno, strerror(errno));
+ // Free the hdr in case we return before calling deliver_request()
if (hdr)
free(hdr);
DNSServiceRefDeallocate(*sdRef);
@@ -1861,7 +2075,7 @@ DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *
if (!pid && setsockopt((*sdRef)->sockfd, SOL_SOCKET, SO_DELEGATED_UUID, uuid, sizeof(uuid_t)) == -1)
{
- syslog(LOG_WARNING, "dnssdclientstub: Could not setsockopt() for UUID, no entitlements or process(uuid) invalid errno:%d (%s) ", errno, strerror(errno));
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceCreateDelegateConnection: Could not setsockopt() for UUID, no entitlements or process(uuid) invalid errno:%d (%s) ", errno, strerror(errno));
// Free the hdr in case we return before calling deliver_request()
if (hdr)
free(hdr);
@@ -1880,7 +2094,7 @@ DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *
}
return err;
}
-#elif TARGET_IPHONE_SIMULATOR // This hack is for Simulator platform only
+#elif TARGET_OS_SIMULATOR // This hack is for Simulator platform only
DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *sdRef, int32_t pid, uuid_t uuid)
{
(void) pid;
@@ -1905,14 +2119,17 @@ DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
void *context
)
{
+ DNSServiceErrorType err;
char *ptr;
size_t len;
ipc_msg_hdr *hdr = NULL;
DNSRecordRef rref = NULL;
DNSRecord **p;
+ // Verify that only one of the following flags is set.
int f1 = (flags & kDNSServiceFlagsShared) != 0;
int f2 = (flags & kDNSServiceFlagsUnique) != 0;
- if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
+ int f3 = (flags & kDNSServiceFlagsKnownUnique) != 0;
+ if (f1 + f2 + f3 != 1) return kDNSServiceErr_BadParam;
if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
flags |= kDNSServiceFlagsIncludeP2P;
@@ -1981,7 +2198,14 @@ DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
while (*p) p = &(*p)->recnext;
*p = rref;
- return deliver_request(hdr, sdRef); // Will free hdr for us
+ err = deliver_request(hdr, sdRef); // Will free hdr for us
+#if CHECK_BUNDLE_VERSION
+ if (err == kDNSServiceErr_NoAuth && !_should_return_noauth_error())
+ {
+ err = kDNSServiceErr_NoError;
+ }
+#endif
+ return err;
}
// sdRef returned by DNSServiceRegister()
@@ -2276,13 +2500,13 @@ DNSServiceErrorType DNSSD_API DNSServiceSetDispatchQueue
}
if (service->disp_source)
{
- syslog(LOG_WARNING, "DNSServiceSetDispatchQueue dispatch source set already");
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSetDispatchQueue dispatch source set already");
return kDNSServiceErr_BadParam;
}
service->disp_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, dnssd_fd, 0, queue);
if (!service->disp_source)
{
- syslog(LOG_WARNING, "DNSServiceSetDispatchQueue dispatch_source_create failed");
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSetDispatchQueue dispatch_source_create failed");
return kDNSServiceErr_NoMemory;
}
service->disp_queue = queue;
@@ -2303,12 +2527,23 @@ static void DNSSD_API SleepKeepaliveCallback(DNSServiceRef sdRef, DNSRecordRef r
(void)flags; // Unused
if (sdRef->kacontext != context)
- syslog(LOG_WARNING, "SleepKeepaliveCallback context mismatch");
+ syslog(LOG_WARNING, "dnssd_clientstub SleepKeepaliveCallback context mismatch");
if (ka->AppCallback)
((DNSServiceSleepKeepaliveReply)ka->AppCallback)(sdRef, errorCode, ka->AppContext);
}
+static DNSServiceErrorType _DNSServiceSleepKeepalive_sockaddr
+(
+ DNSServiceRef * sdRef,
+ DNSServiceFlags flags,
+ const struct sockaddr * localAddr,
+ const struct sockaddr * remoteAddr,
+ unsigned int timeout,
+ DNSServiceSleepKeepaliveReply callBack,
+ void * context
+);
+
DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive
(
DNSServiceRef *sdRef,
@@ -2319,60 +2554,87 @@ DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive
void *context
)
{
- char source_str[INET6_ADDRSTRLEN];
- char target_str[INET6_ADDRSTRLEN];
struct sockaddr_storage lss;
struct sockaddr_storage rss;
socklen_t len1, len2;
- unsigned int len, proxyreclen;
- char buf[256];
- DNSServiceErrorType err;
- DNSRecordRef record = NULL;
- char name[10];
- char recname[128];
- SleepKAContext *ka;
- unsigned int i, unique;
-
-
- (void) flags; //unused
- if (!timeout) return kDNSServiceErr_BadParam;
-
len1 = sizeof(lss);
if (getsockname(fd, (struct sockaddr *)&lss, &len1) < 0)
{
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive: getsockname %d\n", errno);
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive: getsockname %d\n", errno);
return kDNSServiceErr_BadParam;
}
len2 = sizeof(rss);
if (getpeername(fd, (struct sockaddr *)&rss, &len2) < 0)
{
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive: getpeername %d\n", errno);
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive: getpeername %d\n", errno);
return kDNSServiceErr_BadParam;
}
if (len1 != len2)
{
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive local/remote info not same");
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive local/remote info not same");
return kDNSServiceErr_Unknown;
}
+ return _DNSServiceSleepKeepalive_sockaddr(sdRef, flags, (const struct sockaddr *)&lss, (const struct sockaddr *)&rss,
+ timeout, callBack, context);
+}
+
+DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive_sockaddr
+(
+ DNSServiceRef * sdRef,
+ DNSServiceFlags flags,
+ const struct sockaddr * localAddr,
+ const struct sockaddr * remoteAddr,
+ unsigned int timeout,
+ DNSServiceSleepKeepaliveReply callBack,
+ void * context
+)
+{
+ return _DNSServiceSleepKeepalive_sockaddr(sdRef, flags, localAddr, remoteAddr, timeout, callBack, context );
+}
+
+static DNSServiceErrorType _DNSServiceSleepKeepalive_sockaddr
+(
+ DNSServiceRef * sdRef,
+ DNSServiceFlags flags,
+ const struct sockaddr * localAddr,
+ const struct sockaddr * remoteAddr,
+ unsigned int timeout,
+ DNSServiceSleepKeepaliveReply callBack,
+ void * context
+)
+{
+ char source_str[INET6_ADDRSTRLEN];
+ char target_str[INET6_ADDRSTRLEN];
+ unsigned int len, proxyreclen;
+ char buf[256];
+ DNSServiceErrorType err;
+ DNSRecordRef record = NULL;
+ char name[10];
+ char recname[128];
+ SleepKAContext *ka;
+ unsigned int i, unique;
+
+ (void) flags; //unused
+ if (!timeout) return kDNSServiceErr_BadParam;
unique = 0;
- if (lss.ss_family == AF_INET)
+ if ((localAddr->sa_family == AF_INET) && (remoteAddr->sa_family == AF_INET))
{
- struct sockaddr_in *sl = (struct sockaddr_in *)&lss;
- struct sockaddr_in *sr = (struct sockaddr_in *)&rss;
+ const struct sockaddr_in *sl = (const struct sockaddr_in *)localAddr;
+ const struct sockaddr_in *sr = (const struct sockaddr_in *)remoteAddr;
unsigned char *ptr = (unsigned char *)&sl->sin_addr;
if (!inet_ntop(AF_INET, (const void *)&sr->sin_addr, target_str, sizeof (target_str)))
{
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive remote info failed %d", errno);
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive remote info failed %d", errno);
return kDNSServiceErr_Unknown;
}
if (!inet_ntop(AF_INET, (const void *)&sl->sin_addr, source_str, sizeof (source_str)))
{
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive local info failed %d", errno);
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive local info failed %d", errno);
return kDNSServiceErr_Unknown;
}
// Sum of all bytes in the local address and port should result in a unique
@@ -2382,20 +2644,20 @@ DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive
unique += sl->sin_port;
len = snprintf(buf+1, sizeof(buf) - 1, "t=%u h=%s d=%s l=%u r=%u", timeout, source_str, target_str, ntohs(sl->sin_port), ntohs(sr->sin_port));
}
- else
+ else if ((localAddr->sa_family == AF_INET6) && (remoteAddr->sa_family == AF_INET6))
{
- struct sockaddr_in6 *sl6 = (struct sockaddr_in6 *)&lss;
- struct sockaddr_in6 *sr6 = (struct sockaddr_in6 *)&rss;
+ const struct sockaddr_in6 *sl6 = (const struct sockaddr_in6 *)localAddr;
+ const struct sockaddr_in6 *sr6 = (const struct sockaddr_in6 *)remoteAddr;
unsigned char *ptr = (unsigned char *)&sl6->sin6_addr;
if (!inet_ntop(AF_INET6, (const void *)&sr6->sin6_addr, target_str, sizeof (target_str)))
{
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive remote6 info failed %d", errno);
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive remote6 info failed %d", errno);
return kDNSServiceErr_Unknown;
}
if (!inet_ntop(AF_INET6, (const void *)&sl6->sin6_addr, source_str, sizeof (source_str)))
{
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive local6 info failed %d", errno);
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive local6 info failed %d", errno);
return kDNSServiceErr_Unknown;
}
for (i = 0; i < sizeof(struct in6_addr); i++)
@@ -2403,10 +2665,14 @@ DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive
unique += sl6->sin6_port;
len = snprintf(buf+1, sizeof(buf) - 1, "t=%u H=%s D=%s l=%u r=%u", timeout, source_str, target_str, ntohs(sl6->sin6_port), ntohs(sr6->sin6_port));
}
+ else
+ {
+ return kDNSServiceErr_BadParam;
+ }
if (len >= (sizeof(buf) - 1))
{
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive could not fit local/remote info");
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive could not fit local/remote info");
return kDNSServiceErr_Unknown;
}
// Include the NULL byte also in the first byte. The total length of the record includes the
@@ -2417,14 +2683,14 @@ DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive
len = snprintf(name, sizeof(name), "%u", unique);
if (len >= sizeof(name))
{
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive could not fit unique");
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive could not fit unique");
return kDNSServiceErr_Unknown;
}
len = snprintf(recname, sizeof(recname), "%s.%s", name, "_keepalive._dns-sd._udp.local");
if (len >= sizeof(recname))
{
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive could not fit name");
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive could not fit name");
return kDNSServiceErr_Unknown;
}
@@ -2436,7 +2702,7 @@ DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive
err = DNSServiceCreateConnection(sdRef);
if (err)
{
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive cannot create connection");
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive cannot create connection");
free(ka);
return err;
}
@@ -2446,7 +2712,7 @@ DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive
kDNSServiceType_NULL, kDNSServiceClass_IN, proxyreclen, buf, kDNSServiceInterfaceIndexAny, SleepKeepaliveCallback, ka);
if (err)
{
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive cannot create connection");
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive cannot create connection");
free(ka);
return err;
}
diff --git a/usr/src/contrib/mDNSResponder/mDNSShared/dnssd_ipc.c b/usr/src/contrib/mDNSResponder/mDNSShared/dnssd_ipc.c
index 0fd75824f5..a149678ef6 100644
--- a/usr/src/contrib/mDNSResponder/mDNSShared/dnssd_ipc.c
+++ b/usr/src/contrib/mDNSResponder/mDNSShared/dnssd_ipc.c
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2011 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2003-2020 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -27,6 +26,9 @@
*/
#include "dnssd_ipc.h"
+#if APPLE_OSX_mDNSResponder
+#include "mdns_tlv.h"
+#endif
#if defined(_WIN32)
@@ -102,9 +104,11 @@ uint16_t get_uint16(const char **ptr, const char *end)
int put_string(const char *str, char **ptr)
{
+ size_t len;
if (!str) str = "";
- strcpy(*ptr, str);
- *ptr += strlen(str) + 1;
+ len = strlen(str) + 1;
+ memcpy(*ptr, str, len);
+ *ptr += len;
return 0;
}
@@ -151,6 +155,20 @@ const char *get_rdata(const char **ptr, const char *end, int rdlen)
}
}
+#if APPLE_OSX_mDNSResponder
+size_t get_required_tlv16_length(const uint16_t valuelen)
+{
+ return mdns_tlv16_get_required_length(valuelen);
+}
+
+void put_tlv16(const uint16_t type, const uint16_t length, const uint8_t *value, char **ptr)
+{
+ uint8_t *dst = (uint8_t *)*ptr;
+ mdns_tlv16_set(dst, NULL, type, length, value, &dst);
+ *ptr = (char *)dst;
+}
+#endif
+
void ConvertHeaderBytes(ipc_msg_hdr *hdr)
{
hdr->version = htonl(hdr->version);
diff --git a/usr/src/contrib/mDNSResponder/mDNSShared/dnssd_ipc.h b/usr/src/contrib/mDNSResponder/mDNSShared/dnssd_ipc.h
index c054188453..4cf83700df 100644
--- a/usr/src/contrib/mDNSResponder/mDNSShared/dnssd_ipc.h
+++ b/usr/src/contrib/mDNSResponder/mDNSShared/dnssd_ipc.h
@@ -1,6 +1,6 @@
/* -*- Mode: C; tab-width: 4 -*-
*
- * Copyright (c) 2003-2015 Apple Inc. All rights reserved.
+ * Copyright (c) 2003-2020 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -100,7 +100,11 @@ extern char *win32_strerror(int inErrorCode);
// IPC data encoding constants and types
#define VERSION 1
-#define IPC_FLAGS_NOREPLY 1 // set flag if no asynchronous replies are to be sent to client
+#define IPC_FLAGS_NOREPLY (1U << 0) // Set flag if no asynchronous replies are to be sent to client.
+#define IPC_FLAGS_TRAILING_TLVS (1U << 1) // Set flag if TLVs follow the standard request data.
+
+#define IPC_TLV_TYPE_RESOLVER_CONFIG_PLIST_DATA 1 // An nw_resolver_config as a binary property list.
+#define IPC_TLV_TYPE_REQUIRE_PRIVACY 2 // A uint8. Non-zero means privacy is required, zero means not required.
// Structure packing macro. If we're not using GNUC, it's not fatal. Most compilers naturally pack the on-the-wire
// structures correctly anyway, so a plain "struct" is usually fine. In the event that structures are not packed
@@ -211,6 +215,11 @@ void put_rdata(const int rdlen, const unsigned char *rdata, char **ptr);
const char *get_rdata(const char **ptr, const char *end, int rdlen); // return value is rdata pointed to by *ptr -
// rdata is not copied from buffer.
+#if APPLE_OSX_mDNSResponder
+size_t get_required_tlv16_length(const uint16_t valuelen);
+void put_tlv16(const uint16_t type, const uint16_t length, const uint8_t *value, char **ptr);
+#endif
+
void ConvertHeaderBytes(ipc_msg_hdr *hdr);
struct CompileTimeAssertionChecks_dnssd_ipc
diff --git a/usr/src/contrib/mDNSResponder/mDNSShared/mDNSDebug.c b/usr/src/contrib/mDNSResponder/mDNSShared/mDNSDebug.c
index e76ae419bb..f7b2644a01 100644
--- a/usr/src/contrib/mDNSResponder/mDNSShared/mDNSDebug.c
+++ b/usr/src/contrib/mDNSResponder/mDNSShared/mDNSDebug.c
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2018 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2003-2019 Apple Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,8 +14,6 @@
* limitations under the License.
*/
-#include "mDNSDebug.h"
-
#include <stdio.h>
#if defined(WIN32) || defined(EFI32) || defined(EFI64) || defined(EFIX64)
@@ -47,37 +44,49 @@ mDNSexport int mDNS_DebugMode = mDNSfalse;
mDNSexport void verbosedebugf_(const char *format, ...)
{
char buffer[512];
- va_list ptr;
- va_start(ptr,format);
- buffer[mDNS_vsnprintf(buffer, sizeof(buffer), format, ptr)] = 0;
- va_end(ptr);
+ va_list args;
+ va_start(args, format);
+ buffer[mDNS_vsnprintf(buffer, sizeof(buffer), format, args)] = 0;
+ va_end(args);
mDNSPlatformWriteDebugMsg(buffer);
}
#endif
// Log message with default "mDNSResponder" ident string at the start
-mDNSlocal void LogMsgWithLevelv(mDNSLogLevel_t logLevel, const char *format, va_list ptr)
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+mDNSlocal void LogMsgWithLevelv(os_log_t category, os_log_type_t level, const char *format, va_list args)
+{
+ char buffer[512];
+ mDNS_vsnprintf(buffer, (mDNSu32)sizeof(buffer), format, args);
+ os_log_with_type(category ? category : mDNSLogCategory_Default, level, "%{private}s", buffer);
+}
+#else
+mDNSlocal void LogMsgWithLevelv(const char *category, mDNSLogLevel_t level, const char *format, va_list args)
{
char buffer[512];
- buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
- mDNSPlatformWriteLogMsg(ProgramName, buffer, logLevel);
+ char *dst = buffer;
+ const char *const lim = &buffer[512];
+ if (category) mDNS_snprintf_add(&dst, lim, "%s: ", category);
+ mDNS_vsnprintf(dst, (mDNSu32)(lim - dst), format, args);
+ mDNSPlatformWriteLogMsg(ProgramName, buffer, level);
}
+#endif
-#define LOG_HELPER_BODY(L) \
+#define LOG_HELPER_BODY(CATEGORY, LEVEL) \
{ \
- va_list ptr; \
- va_start(ptr,format); \
- LogMsgWithLevelv(L, format, ptr); \
- va_end(ptr); \
+ va_list args; \
+ va_start(args,format); \
+ LogMsgWithLevelv(CATEGORY, LEVEL, format, args); \
+ va_end(args); \
}
// see mDNSDebug.h
#if !MDNS_HAS_VA_ARG_MACROS
-void LogMsg_(const char *format, ...) LOG_HELPER_BODY(MDNS_LOG_MSG)
-void LogOperation_(const char *format, ...) LOG_HELPER_BODY(MDNS_LOG_OPERATION)
-void LogSPS_(const char *format, ...) LOG_HELPER_BODY(MDNS_LOG_SPS)
-void LogInfo_(const char *format, ...) LOG_HELPER_BODY(MDNS_LOG_INFO)
-void LogDebug_(const char *format, ...) LOG_HELPER_BODY(MDNS_LOG_DEBUG)
+void LogMsg_(const char *format, ...) LOG_HELPER_BODY(NULL, MDNS_LOG_INFO)
+void LogOperation_(const char *format, ...) LOG_HELPER_BODY(NULL, MDNS_LOG_INFO)
+void LogSPS_(const char *format, ...) LOG_HELPER_BODY(NULL, MDNS_LOG_INFO)
+void LogInfo_(const char *format, ...) LOG_HELPER_BODY(NULL, MDNS_LOG_INFO)
+void LogDebug_(const char *format, ...) LOG_HELPER_BODY(NULL, MDNS_LOG_DEBUG)
#endif
#if MDNS_DEBUGMSGS
@@ -85,5 +94,20 @@ void debugf_(const char *format, ...) LOG_HELPER_BODY(MDNS_LOG_DEBUG)
#endif
// Log message with default "mDNSResponder" ident string at the start
-mDNSexport void LogMsgWithLevel(mDNSLogLevel_t logLevel, const char *format, ...)
-LOG_HELPER_BODY(logLevel)
+mDNSexport void LogMsgWithLevel(mDNSLogCategory_t category, mDNSLogLevel_t level, const char *format, ...)
+LOG_HELPER_BODY(category, level)
+
+mDNSexport void LogToFD(int fd, const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+#if APPLE_OSX_mDNSResponder
+ char buffer[1024];
+ buffer[mDNS_vsnprintf(buffer, (mDNSu32)sizeof(buffer), format, args)] = '\0';
+ dprintf(fd, "%s\n", buffer);
+#else
+ (void)fd;
+ LogMsgWithLevelv(NULL, MDNS_LOG_INFO, format, args);
+#endif
+ va_end(args);
+}
diff --git a/usr/src/contrib/mDNSResponder/mDNSShared/mDNSFeatures.h b/usr/src/contrib/mDNSResponder/mDNSShared/mDNSFeatures.h
new file mode 100644
index 0000000000..3f2f79e925
--- /dev/null
+++ b/usr/src/contrib/mDNSResponder/mDNSShared/mDNSFeatures.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2019 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __mDNSFeatures_h
+#define __mDNSFeatures_h
+
+#if MDNSRESPONDER_PLATFORM_APPLE
+#include "ApplePlatformFeatures.h"
+#endif
+
+// Common Features
+
+#undef MDNSRESPONDER_PLATFORM_COMMON
+#define MDNSRESPONDER_PLATFORM_COMMON 1
+
+// Feature: DNS Push
+// Radar: <rdar://problem/23226275>
+// Enabled: Yes, for Apple.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_COMMON_DNS_PUSH)
+ #if defined(MDNSRESPONDER_PLATFORM_APPLE) && MDNSRESPONDER_PLATFORM_APPLE
+ #define MDNSRESPONDER_SUPPORTS_COMMON_DNS_PUSH 1
+ #else
+ #define MDNSRESPONDER_SUPPORTS_COMMON_DNS_PUSH 0
+ #endif
+#endif
+
+#define HAS_FEATURE_CAT(A, B) A ## B
+#define HAS_FEATURE_CHECK_0 1
+#define HAS_FEATURE_CHECK_1 1
+#define HAS_FEATURE(X) ((X) / HAS_FEATURE_CAT(HAS_FEATURE_CHECK_, X))
+
+#define MDNSRESPONDER_SUPPORTS(PLATFORM, FEATURE) \
+ (defined(MDNSRESPONDER_PLATFORM_ ## PLATFORM) && MDNSRESPONDER_PLATFORM_ ## PLATFORM && \
+ HAS_FEATURE(MDNSRESPONDER_SUPPORTS_ ## PLATFORM ## _ ## FEATURE))
+
+#endif // __mDNSFeatures_h
diff --git a/usr/src/contrib/mDNSResponder/mDNSShared/uds_daemon.c b/usr/src/contrib/mDNSResponder/mDNSShared/uds_daemon.c
index 35b65f6608..fba7721356 100644
--- a/usr/src/contrib/mDNSResponder/mDNSShared/uds_daemon.c
+++ b/usr/src/contrib/mDNSResponder/mDNSShared/uds_daemon.c
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2018 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2003-2020 Apple Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -36,19 +35,12 @@
#include "uds_daemon.h"
#include "dns_sd_internal.h"
-// Normally we append search domains only for queries with a single label that are not
-// fully qualified. This can be overridden to apply search domains for queries (that are
-// not fully qualified) with any number of labels e.g., moon, moon.cs, moon.cs.be, etc.
-mDNSBool AlwaysAppendSearchDomains = mDNSfalse;
-
-// Control enabling ioptimistic DNS
-mDNSBool EnableAllowExpired = mDNStrue;
-
// Apple-specific functionality, not required for other platforms
#if APPLE_OSX_mDNSResponder
+#include <os/log.h>
#include <sys/ucred.h>
#ifndef PID_FILE
-#define PID_FILE ""
+#define NO_PID_FILE // We need to signal that this platform has no PID file, and not just that we are taking the default
#endif
#endif
@@ -59,34 +51,43 @@ mDNSBool EnableAllowExpired = mDNStrue;
#include <libproc.h> // for proc_pidinfo()
#endif //LOCAL_PEEREPID
-#ifdef UNIT_TEST
-#include "unittest.h"
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+#include "D2D.h"
#endif
#if APPLE_OSX_mDNSResponder
-#include <WebFilterDNS/WebFilterDNS.h>
#include "BLE.h"
+#endif
-#if !NO_WCF
+#if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
+#include "mDNSMacOSX.h"
+#include <os/feature_private.h>
+#endif
-int WCFIsServerRunning(WCFConnection *conn) __attribute__((weak_import));
-int WCFNameResolvesToAddr(WCFConnection *conn, char* domainName, struct sockaddr* address, uid_t userid) __attribute__((weak_import));
-int WCFNameResolvesToName(WCFConnection *conn, char* fromName, char* toName, uid_t userid) __attribute__((weak_import));
+#if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
+#include <bsm/libbsm.h>
+#endif
-// Do we really need to define a macro for "if"?
-#define CHECK_WCF_FUNCTION(X) if (X)
-#endif // ! NO_WCF
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+#include "QuerierSupport.h"
+#endif
-#else
-#define NO_WCF 1
-#endif // APPLE_OSX_mDNSResponder
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER) && MDNSRESPONDER_SUPPORTS(APPLE, IPC_TLV)
+#include "mdns_tlv.h"
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+#include "dnssec_v2.h"
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSD_XPC_SERVICE)
+#include "dnssd_server.h"
+#endif
// User IDs 0-500 are system-wide processes, not actual users in the usual sense
// User IDs for real user accounts start at 501 and count up from there
#define SystemUID(X) ((X) <= 500)
-#define MAX_ANONYMOUS_DATA 256
-
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
@@ -119,12 +120,11 @@ static mDNSu32 n_mrecords; // tracks the current active mcast records for McastL
static mDNSu32 n_mquests; // tracks the current active mcast questions for McastLogging
-#if TARGET_OS_EMBEDDED
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
mDNSu32 curr_num_regservices = 0;
mDNSu32 max_num_regservices = 0;
#endif
-
// Note asymmetry here between registration and browsing.
// For service registrations we only automatically register in domains that explicitly appear in local configuration data
// (so AutoRegistrationDomains could equally well be called SCPrefRegDomains)
@@ -149,14 +149,22 @@ mDNSexport DNameListElem *AutoBrowseDomains; // List created from those l
#define PID_FILE "/var/run/mDNSResponder.pid"
#endif
-mDNSlocal char *AnonDataToString(const mDNSu8 *ad, int adlen, char *adstr, int adstrlen);
-
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
#pragma mark - General Utility Functions
#endif
+mDNSlocal mDNSu32 GetNewRequestID(void)
+{
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSD_XPC_SERVICE)
+ return dnssd_server_get_new_request_id();
+#else
+ static mDNSu32 s_last_id = 0;
+ return ++s_last_id;
+#endif
+}
+
mDNSlocal void FatalError(char *errmsg)
{
LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno));
@@ -315,21 +323,44 @@ mDNSexport void LogMcastStateInfo(mDNSBool mflag, mDNSBool start, mDNSBool mstat
mDNSlocal void abort_request(request_state *req)
{
if (req->terminate == (req_termination_fn) ~0)
- { LogMsg("abort_request: ERROR: Attempt to abort operation %p with req->terminate %p", req, req->terminate); return; }
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%d] abort_request: ERROR: Attempt to abort operation %p with req->terminate %p", req->request_id, req, req->terminate);
+ return;
+ }
// First stop whatever mDNSCore operation we were doing
// If this is actually a shared connection operation, then its req->terminate function will scan
// the all_requests list and terminate any subbordinate operations sharing this file descriptor
if (req->terminate) req->terminate(req);
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ if (req->custom_service_id != 0)
+ {
+ Querier_DeregisterCustomDNSService(req->custom_service_id);
+ req->custom_service_id = 0;
+ }
+#endif
if (!dnssd_SocketValid(req->sd))
- { LogMsg("abort_request: ERROR: Attempt to abort operation %p with invalid fd %d", req, req->sd); return; }
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%d] abort_request: ERROR: Attempt to abort operation %p with invalid fd %d", req->request_id, req, req->sd);
+ return;
+ }
// Now, if this request_state is not subordinate to some other primary, close file descriptor and discard replies
if (!req->primary)
{
- if (req->errsd != req->sd) LogDebug("%3d: Removing FD and closing errsd %d", req->sd, req->errsd);
- else LogDebug("%3d: Removing FD", req->sd);
+ if (req->errsd != req->sd)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+ "[R%d] Removing FD %d and closing errsd %d", req->request_id, req->sd, req->errsd);
+ }
+ else
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+ "[R%d] Removing FD %d", req->request_id, req->sd);
+ }
udsSupportRemoveFDFromEventLoop(req->sd, req->platform_data); // Note: This also closes file descriptor req->sd for us
if (req->errsd != req->sd) { dnssd_close(req->errsd); req->errsd = req->sd; }
@@ -342,9 +373,12 @@ mDNSlocal void abort_request(request_state *req)
}
// Set req->sd to something invalid, so that udsserver_idle knows to unlink and free this structure
-#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
- // Don't use dnssd_InvalidSocket (-1) because that's the sentinel value MACOSX_MDNS_MALLOC_DEBUGGING uses
+#if MDNS_MALLOC_DEBUGGING
+ // Don't use dnssd_InvalidSocket (-1) because that's the sentinel value MDNS_MALLOC_DEBUGGING uses
// for detecting when the memory for an object is inadvertently freed while the object is still on some list
+#ifdef WIN32
+#error This will not work on Windows, look at IsValidSocket in mDNSShared/CommonServices.h to see why
+#endif
req->sd = req->errsd = -2;
#else
req->sd = req->errsd = dnssd_InvalidSocket;
@@ -376,7 +410,20 @@ mDNSlocal void AbortUnlinkAndFree(request_state *req)
request_state **p = &all_requests;
abort_request(req);
while (*p && *p != req) p=&(*p)->next;
- if (*p) { *p = req->next; freeL("request_state/AbortUnlinkAndFree", req); }
+ if (*p)
+ {
+ *p = req->next;
+#if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
+ if (req->trust)
+ {
+ void * context = mdns_trust_get_context(req->trust);
+ mdns_trust_set_context(req->trust, NULL);
+ if (context) freeL("context/AbortUnlinkAndFree", context);
+ mdns_trust_forget(&req->trust);
+ }
+#endif
+ freeL("request_state/AbortUnlinkAndFree", req);
+ }
else LogMsg("AbortUnlinkAndFree: ERROR: Attempt to abort operation %p not in list", req);
}
@@ -390,8 +437,8 @@ mDNSlocal reply_state *create_reply(const reply_op_t op, const size_t datalen, r
return NULL;
}
- reply = mallocL("reply_state", sizeof(reply_state) + datalen - sizeof(reply_hdr));
- if (!reply) FatalError("ERROR: malloc");
+ reply = (reply_state *) callocL("reply_state", sizeof(reply_state) + datalen - sizeof(reply_hdr));
+ if (!reply) FatalError("ERROR: calloc");
reply->next = mDNSNULL;
reply->totallen = (mDNSu32)datalen + sizeof(ipc_msg_hdr);
@@ -437,7 +484,7 @@ mDNSlocal mStatus GenerateNTDResponse(const domainname *const servicename, const
domainlabel name;
domainname type, dom;
*rep = NULL;
- if (!DeconstructServiceName(servicename, &name, &type, &dom))
+ if (servicename && !DeconstructServiceName(servicename, &name, &type, &dom))
return kDNSServiceErr_Invalid;
else
{
@@ -447,9 +494,18 @@ mDNSlocal mStatus GenerateNTDResponse(const domainname *const servicename, const
int len;
char *data;
- ConvertDomainLabelToCString_unescaped(&name, namestr);
- ConvertDomainNameToCString(&type, typestr);
- ConvertDomainNameToCString(&dom, domstr);
+ if (servicename)
+ {
+ ConvertDomainLabelToCString_unescaped(&name, namestr);
+ ConvertDomainNameToCString(&type, typestr);
+ ConvertDomainNameToCString(&dom, domstr);
+ }
+ else
+ {
+ namestr[0] = 0;
+ typestr[0] = 0;
+ domstr[0] = 0;
+ }
// Calculate reply data length
len = sizeof(DNSServiceFlags);
@@ -486,11 +542,19 @@ mDNSlocal void GenerateBrowseReply(const domainname *const servicename, const mD
*rep = NULL;
- // 1. Put first label in namestr
- ConvertDomainLabelToCString_unescaped((const domainlabel *)servicename, namestr);
+ if (servicename)
+ {
+ // 1. Put first label in namestr
+ ConvertDomainLabelToCString_unescaped((const domainlabel *)servicename, namestr);
- // 2. Put second label and "local" into typestr
- mDNS_snprintf(typestr, sizeof(typestr), "%#s.local.", SecondLabel(servicename));
+ // 2. Put second label and "local" into typestr
+ mDNS_snprintf(typestr, sizeof(typestr), "%#s.local.", SecondLabel(servicename));
+ }
+ else
+ {
+ namestr[0] = 0;
+ typestr[0] = 0;
+ }
// Calculate reply data length
len = sizeof(DNSServiceFlags);
@@ -520,17 +584,18 @@ mDNSlocal AuthRecord *read_rr_from_ipc_msg(request_state *request, int GetTTL, i
{
DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
- char name[256];
+ char name[MAX_ESCAPED_DOMAIN_NAME];
int str_err = get_string(&request->msgptr, request->msgend, name, sizeof(name));
mDNSu16 type = get_uint16(&request->msgptr, request->msgend);
mDNSu16 class = get_uint16(&request->msgptr, request->msgend);
mDNSu16 rdlen = get_uint16(&request->msgptr, request->msgend);
- const char *rdata = get_rdata (&request->msgptr, request->msgend, rdlen);
+ const mDNSu8 *const rdata = (const mDNSu8 *)get_rdata (&request->msgptr, request->msgend, rdlen);
mDNSu32 ttl = GetTTL ? get_uint32(&request->msgptr, request->msgend) : 0;
- size_t storage_size = rdlen > sizeof(RDataBody) ? rdlen : sizeof(RDataBody);
+ size_t rdcapacity;
AuthRecord *rr;
mDNSInterfaceID InterfaceID;
AuthRecType artype;
+ mDNSu8 recordType;
request->flags = flags;
request->interfaceIndex = interfaceIndex;
@@ -541,16 +606,32 @@ mDNSlocal AuthRecord *read_rr_from_ipc_msg(request_state *request, int GetTTL, i
if (validate_flags &&
!((flags & kDNSServiceFlagsShared) == kDNSServiceFlagsShared) &&
- !((flags & kDNSServiceFlagsUnique) == kDNSServiceFlagsUnique))
+ !((flags & kDNSServiceFlagsUnique) == kDNSServiceFlagsUnique) &&
+ !((flags & kDNSServiceFlagsKnownUnique) == kDNSServiceFlagsKnownUnique))
{
- LogMsg("ERROR: Bad resource record flags (must be kDNSServiceFlagsShared or kDNSServiceFlagsUnique)");
+ LogMsg("ERROR: Bad resource record flags (must be one of either kDNSServiceFlagsShared, kDNSServiceFlagsUnique or kDNSServiceFlagsKnownUnique)");
return NULL;
}
+ InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
- rr = mallocL("AuthRecord/read_rr_from_ipc_msg", sizeof(AuthRecord) - sizeof(RDataBody) + storage_size);
- if (!rr) FatalError("ERROR: malloc");
+ // The registration is scoped to a specific interface index, but the interface is not currently on our list.
+ if ((InterfaceID == mDNSInterface_Any) && (interfaceIndex != kDNSServiceInterfaceIndexAny))
+ {
+ // On Apple platforms, an interface's mDNSInterfaceID is equal to its index. Using an interface index that isn't
+ // currently valid will cause the registration to take place as soon as it becomes valid. On other platforms,
+ // mDNSInterfaceID is actually a pointer to a platform-specific interface object, but we don't know what the pointer
+ // for the interface index will be ahead of time. For now, just return NULL to indicate an error condition since the
+ // interface index is invalid. Otherwise, the registration would be performed on all interfaces.
+#if APPLE_OSX_mDNSResponder
+ InterfaceID = (mDNSInterfaceID)(uintptr_t)interfaceIndex;
+#else
+ return NULL;
+#endif
+ }
+ rdcapacity = (rdlen > sizeof(RDataBody2)) ? rdlen : sizeof(RDataBody2);
+ rr = (AuthRecord *) callocL("AuthRecord/read_rr_from_ipc_msg", sizeof(*rr) - sizeof(RDataBody) + rdcapacity);
+ if (!rr) FatalError("ERROR: calloc");
- InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
if (InterfaceID == mDNSInterface_LocalOnly)
artype = AuthRecordLocalOnly;
else if (InterfaceID == mDNSInterface_P2P || InterfaceID == mDNSInterface_BLE)
@@ -565,8 +646,14 @@ mDNSlocal AuthRecord *read_rr_from_ipc_msg(request_state *request, int GetTTL, i
else
artype = AuthRecordAny;
- mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, type, 0,
- (mDNSu8) ((flags & kDNSServiceFlagsShared) ? kDNSRecordTypeShared : kDNSRecordTypeUnique), artype, mDNSNULL, mDNSNULL);
+ if (flags & kDNSServiceFlagsShared)
+ recordType = (mDNSu8) kDNSRecordTypeShared;
+ else if (flags & kDNSServiceFlagsKnownUnique)
+ recordType = (mDNSu8) kDNSRecordTypeKnownUnique;
+ else
+ recordType = (mDNSu8) kDNSRecordTypeUnique;
+
+ mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, type, 0, recordType, artype, mDNSNULL, mDNSNULL);
if (!MakeDomainNameFromDNSNameString(&rr->namestorage, name))
{
@@ -578,8 +665,15 @@ mDNSlocal AuthRecord *read_rr_from_ipc_msg(request_state *request, int GetTTL, i
if (flags & kDNSServiceFlagsAllowRemoteQuery) rr->AllowRemoteQuery = mDNStrue;
rr->resrec.rrclass = class;
rr->resrec.rdlength = rdlen;
- rr->resrec.rdata->MaxRDLength = rdlen;
- mDNSPlatformMemCopy(rr->resrec.rdata->u.data, rdata, rdlen);
+ rr->resrec.rdata->MaxRDLength = (mDNSu16)rdcapacity;
+ if (!SetRData(mDNSNULL, rdata, rdata + rdlen, &rr->resrec, rdlen))
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[R%u] read_rr_from_ipc_msg: SetRData failed for " PRI_DM_NAME " (" PUB_S ")",
+ request->request_id, DM_NAME_PARAM(rr->resrec.name), DNSTypeName(type));
+ freeL("AuthRecord/read_rr_from_ipc_msg", rr);
+ return NULL;
+ }
if (GetTTL) rr->resrec.rroriginalttl = ttl;
rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
@@ -600,13 +694,15 @@ mDNSlocal int build_domainname_from_strings(domainname *srv, char *name, char *r
mDNSlocal void send_all(dnssd_sock_t s, const char *ptr, int len)
{
- int n = send(s, ptr, len, 0);
+ const ssize_t n = send(s, ptr, len, 0);
// On a freshly-created Unix Domain Socket, the kernel should *never* fail to buffer a small write for us
// (four bytes for a typical error code return, 12 bytes for DNSServiceGetProperty(DaemonVersion)).
// If it does fail, we don't attempt to handle this failure, but we do log it so we know something is wrong.
if (n < len)
- LogMsg("ERROR: send_all(%d) wrote %d of %d errno %d (%s)",
- s, n, len, dnssd_errno, dnssd_strerror(dnssd_errno));
+ {
+ LogMsg("ERROR: send_all(%d) wrote %ld of %d errno %d (%s)",
+ s, (long)n, len, dnssd_errno, dnssd_strerror(dnssd_errno));
+ }
}
#if 0
@@ -638,40 +734,41 @@ mDNSlocal mDNSBool AuthorizedDomain(const request_state * const request, const d
}
#endif
-// ***************************************************************************
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark -
-#pragma mark - external helpers
-#endif
-
-mDNSexport mDNSBool callExternalHelpers(mDNSInterfaceID InterfaceID, const domainname *const domain, DNSServiceFlags flags)
+#if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
+mDNSlocal void SetupAuditTokenForRequest(request_state *request)
{
-#if APPLE_OSX_mDNSResponder
- // Only call D2D layer routines if request applies to a D2D interface and the domain is "local".
- if ( (((InterfaceID == mDNSInterface_Any) && (flags & (kDNSServiceFlagsIncludeP2P | kDNSServiceFlagsIncludeAWDL | kDNSServiceFlagsAutoTrigger)))
- || mDNSPlatformInterfaceIsD2D(InterfaceID) || (InterfaceID == mDNSInterface_BLE))
- && IsLocalDomain(domain))
+ pid_t audit_pid = audit_token_to_pid(request->audit_token);
+ if (audit_pid == 0)
{
- return mDNStrue;
+#if !defined(LOCAL_PEERTOKEN)
+#define LOCAL_PEERTOKEN 0x006 /* retrieve peer audit token */
+#endif
+ socklen_t len = sizeof(audit_token_t);
+ int ret = getsockopt(request->sd, SOL_LOCAL, LOCAL_PEERTOKEN, &request->audit_token, &len);
+ if (ret != 0)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "SetupAuditTokenForRequest: No audit_token using LOCAL_PEERTOKEN (%s PID %d) for op %d ret(%d)",
+ request->pid_name, request->process_id, request->hdr.op, ret);
+ }
}
- else
- return mDNSfalse;
-
-#else
- (void) InterfaceID;
- (void) domain;
- (void) flags;
-
- return mDNSfalse;
-#endif // APPLE_OSX_mDNSResponder
}
+#endif
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - external helpers
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
mDNSlocal void external_start_advertising_helper(service_instance *const instance)
{
AuthRecord *st = instance->subtypes;
ExtraResourceRecord *e;
int i;
+ const pid_t requestPID = instance->request->process_id;
if (mDNSIPPortIsZero(instance->request->u.servicereg.port))
{
@@ -682,15 +779,14 @@ mDNSlocal void external_start_advertising_helper(service_instance *const instanc
if (instance->external_advertise) LogMsg("external_start_advertising_helper: external_advertise already set!");
for ( i = 0; i < instance->request->u.servicereg.num_subtypes; i++)
- external_start_advertising_service(&st[i].resrec, instance->request->flags);
-
- external_start_advertising_service(&instance->srs.RR_PTR.resrec, instance->request->flags);
- external_start_advertising_service(&instance->srs.RR_SRV.resrec, instance->request->flags);
+ external_start_advertising_service(&st[i].resrec, instance->request->flags, requestPID);
- external_start_advertising_service(&instance->srs.RR_TXT.resrec, instance->request->flags);
+ external_start_advertising_service(&instance->srs.RR_PTR.resrec, instance->request->flags, requestPID);
+ external_start_advertising_service(&instance->srs.RR_SRV.resrec, instance->request->flags, requestPID);
+ external_start_advertising_service(&instance->srs.RR_TXT.resrec, instance->request->flags, requestPID);
for (e = instance->srs.Extras; e; e = e->next)
- external_start_advertising_service(&e->r.resrec, instance->request->flags);
+ external_start_advertising_service(&e->r.resrec, instance->request->flags, requestPID);
instance->external_advertise = mDNStrue;
}
@@ -705,18 +801,41 @@ mDNSlocal void external_stop_advertising_helper(service_instance *const instance
LogInfo("external_stop_advertising_helper: calling external_stop_advertising_service");
- for ( i = 0; i < instance->request->u.servicereg.num_subtypes; i++)
- external_stop_advertising_service(&st[i].resrec, instance->request->flags);
+ if (instance->request)
+ {
+ const pid_t requestPID = instance->request->process_id;
+ for (i = 0; i < instance->request->u.servicereg.num_subtypes; i++)
+ {
+ external_stop_advertising_service(&st[i].resrec, instance->request->flags, requestPID);
+ }
- external_stop_advertising_service(&instance->srs.RR_PTR.resrec, instance->request->flags);
- external_stop_advertising_service(&instance->srs.RR_SRV.resrec, instance->request->flags);
- external_stop_advertising_service(&instance->srs.RR_TXT.resrec, instance->request->flags);
+ external_stop_advertising_service(&instance->srs.RR_PTR.resrec, instance->request->flags, requestPID);
+ external_stop_advertising_service(&instance->srs.RR_SRV.resrec, instance->request->flags, requestPID);
+ external_stop_advertising_service(&instance->srs.RR_TXT.resrec, instance->request->flags, requestPID);
- for (e = instance->srs.Extras; e; e = e->next)
- external_stop_advertising_service(&e->r.resrec, instance->request->flags);
+ for (e = instance->srs.Extras; e; e = e->next)
+ {
+ external_stop_advertising_service(&e->r.resrec, instance->request->flags, requestPID);
+ }
+ }
instance->external_advertise = mDNSfalse;
}
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
+mDNSlocal dispatch_queue_t _get_trust_results_dispatch_queue(void)
+{
+ static dispatch_once_t once = 0;
+ static dispatch_queue_t queue = NULL;
+
+ dispatch_once(&once, ^{
+ dispatch_queue_attr_t const attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_UTILITY, 0);
+ queue = dispatch_queue_create("com.apple.mDNSResponder.trust_results-queue", attr);
+ });
+ return queue;
+}
+#endif
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
@@ -742,7 +861,9 @@ mDNSlocal void unlink_and_free_service_instance(service_instance *srv)
{
ExtraResourceRecord *e = srv->srs.Extras, *tmp;
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
external_stop_advertising_helper(srv);
+#endif
// clear pointers from parent struct
if (srv->request)
@@ -771,11 +892,6 @@ mDNSlocal void unlink_and_free_service_instance(service_instance *srv)
freeL("ServiceSubTypes", srv->subtypes);
srv->subtypes = NULL;
}
- if (srv->srs.AnonData)
- {
- freeL("Anonymous", (void *)srv->srs.AnonData);
- srv->srs.AnonData = NULL;
- }
freeL("service_instance", srv);
}
@@ -827,10 +943,18 @@ mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, m
reply_state *rep;
(void)m; // Unused
- if (!srs) { LogMsg("regservice_callback: srs is NULL %d", result); return; }
+ if (!srs)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "regservice_callback: srs is NULL %d", result);
+ return;
+ }
instance = srs->ServiceContext;
- if (!instance) { LogMsg("regservice_callback: srs->ServiceContext is NULL %d", result); return; }
+ if (!instance)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "regservice_callback: srs->ServiceContext is NULL %d", result);
+ return;
+ }
// don't send errors up to client for wide-area, empty-string registrations
if (instance->request &&
@@ -840,18 +964,33 @@ mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, m
if (mDNS_LoggingEnabled)
{
- const char *const fmt =
- (result == mStatus_NoError) ? "%s DNSServiceRegister(%##s, %u) REGISTERED" :
- (result == mStatus_MemFree) ? "%s DNSServiceRegister(%##s, %u) DEREGISTERED" :
- (result == mStatus_NameConflict) ? "%s DNSServiceRegister(%##s, %u) NAME CONFLICT" :
- "%s DNSServiceRegister(%##s, %u) %s %d";
- char prefix[16] = "---:";
- if (instance->request) mDNS_snprintf(prefix, sizeof(prefix), "%3d:", instance->request->sd);
- LogOperation(fmt, prefix, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port),
- SuppressError ? "suppressed error" : "CALLBACK", result);
+ const char *result_description;
+ char description[32]; // 32-byte is enough for holding "suppressed error -2147483648\0"
+ mDNSu32 request_id = instance->request ? instance->request->request_id : 0;
+ switch (result) {
+ case mStatus_NoError:
+ result_description = "REGISTERED";
+ break;
+ case mStatus_MemFree:
+ result_description = "DEREGISTERED";
+ break;
+ case mStatus_NameConflict:
+ result_description = "NAME CONFLICT";
+ break;
+ default:
+ mDNS_snprintf(description, sizeof(description), "%s %d", SuppressError ? "suppressed error" : "CALLBACK", result);
+ result_description = description;
+ break;
+ }
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%u] DNSServiceRegister(" PRI_DM_NAME ", %u) %s",
+ request_id, DM_NAME_PARAM(srs->RR_SRV.resrec.name), mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port), result_description);
}
- if (!instance->request && result != mStatus_MemFree) { LogMsg("regservice_callback: instance->request is NULL %d", result); return; }
+ if (!instance->request && result != mStatus_MemFree)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "regservice_callback: instance->request is NULL %d", result);
+ return;
+ }
if (result == mStatus_NoError)
{
@@ -866,28 +1005,33 @@ mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, m
}
if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, instance->request, &rep, reg_service_reply_op, kDNSServiceFlagsAdd, result) != mStatus_NoError)
- LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", instance->request->sd, srs->RR_SRV.resrec.name->c);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "[R%u] regservice_callback: " PRI_DM_NAME " is not valid DNS-SD SRV name", instance->request->request_id, DM_NAME_PARAM(srs->RR_SRV.resrec.name));
else { append_reply(instance->request, rep); instance->clientnotified = mDNStrue; }
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
if (callExternalHelpers(instance->request->u.servicereg.InterfaceID, &instance->domain, instance->request->flags))
{
- LogInfo("regservice_callback: calling external_start_advertising_helper()");
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%u] regservice_callback: calling external_start_advertising_helper()", instance->request->request_id);
external_start_advertising_helper(instance);
}
+#endif
if (instance->request->u.servicereg.autoname && CountPeerRegistrations(srs) == 0)
RecordUpdatedNiceLabel(0); // Successfully got new name, tell user immediately
}
else if (result == mStatus_MemFree)
{
-#if TARGET_OS_EMBEDDED
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
curr_num_regservices--;
#endif
if (instance->request && instance->renameonmemfree)
{
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
external_stop_advertising_helper(instance);
+#endif
instance->renameonmemfree = 0;
err = mDNS_RenameAndReregisterService(m, srs, &instance->request->u.servicereg.name);
- if (err) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %d", err);
+ if (err)
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "[R%u] ERROR: regservice_callback - RenameAndReregisterService returned %d", instance->request->request_id, err);
// error should never happen - safest to log and continue
}
else
@@ -897,7 +1041,9 @@ mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, m
{
if (instance->request->u.servicereg.autorename)
{
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
external_stop_advertising_helper(instance);
+#endif
if (instance->request->u.servicereg.autoname && CountPeerRegistrations(srs) == 0)
{
// On conflict for an autoname service, rename and reregister *all* autoname services
@@ -915,7 +1061,7 @@ mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, m
if (!SuppressError)
{
if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, instance->request, &rep, reg_service_reply_op, kDNSServiceFlagsAdd, result) != mStatus_NoError)
- LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", instance->request->sd, srs->RR_SRV.resrec.name->c);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "[R%u] regservice_callback: " PRI_DM_NAME " is not valid DNS-SD SRV name", instance->request->request_id, DM_NAME_PARAM(srs->RR_SRV.resrec.name));
else { append_reply(instance->request, rep); instance->clientnotified = mDNStrue; }
}
unlink_and_free_service_instance(instance);
@@ -926,7 +1072,7 @@ mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, m
if (!SuppressError)
{
if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, instance->request, &rep, reg_service_reply_op, kDNSServiceFlagsAdd, result) != mStatus_NoError)
- LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", instance->request->sd, srs->RR_SRV.resrec.name->c);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "[R%u] regservice_callback: " PRI_DM_NAME " is not valid DNS-SD SRV name", instance->request->request_id, DM_NAME_PARAM(srs->RR_SRV.resrec.name));
else { append_reply(instance->request, rep); instance->clientnotified = mDNStrue; }
}
}
@@ -938,10 +1084,11 @@ mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord *rr, mStatus result)
if (!rr->RecordContext) // parent struct already freed by termination callback
{
if (result == mStatus_NoError)
- LogMsg("Error: regrecord_callback: successful registration of orphaned record %s", ARDisplayString(m, rr));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "Error: regrecord_callback: successful registration of orphaned record " PRI_S, ARDisplayString(m, rr));
else
{
- if (result != mStatus_MemFree) LogMsg("regrecord_callback: error %d received after parent termination", result);
+ if (result != mStatus_MemFree)
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "regrecord_callback: error %d received after parent termination", result);
// We come here when the record is being deregistered either from DNSServiceRemoveRecord or connection_termination.
// If the record has been updated, we need to free the rdata. Every time we call mDNS_Update, it calls update_callback
@@ -958,11 +1105,26 @@ mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord *rr, mStatus result)
if (mDNS_LoggingEnabled)
{
- char *fmt = (result == mStatus_NoError) ? "%3d: DNSServiceRegisterRecord(%u %s) REGISTERED" :
- (result == mStatus_MemFree) ? "%3d: DNSServiceRegisterRecord(%u %s) DEREGISTERED" :
- (result == mStatus_NameConflict) ? "%3d: DNSServiceRegisterRecord(%u %s) NAME CONFLICT" :
- "%3d: DNSServiceRegisterRecord(%u %s) %d";
- LogOperation(fmt, request->sd, re->key, RRDisplayString(m, &rr->resrec), result);
+ const char *result_description;
+ char description[16]; // 16-byte is enough for holding -2147483648\0
+ switch (result) {
+ case mStatus_NoError:
+ result_description = "REGISTERED";
+ break;
+ case mStatus_MemFree:
+ result_description = "DEREGISTERED";
+ break;
+ case mStatus_NameConflict:
+ result_description = "NAME CONFLICT";
+ break;
+ default:
+ mDNS_snprintf(description, sizeof(description), "%d", result);
+ result_description = description;
+ break;
+ }
+
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%u] DNSServiceRegisterRecord(%u " PRI_S ")" PUB_S,
+ request->request_id, re->key, RRDisplayString(m, &rr->resrec), result_description);
}
if (result != mStatus_MemFree)
@@ -981,14 +1143,20 @@ mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord *rr, mStatus result)
// If this is a callback to a keepalive record, do not free it.
if (result == mStatus_BadStateErr)
{
- LogInfo("regrecord_callback: Callback with error code mStatus_BadStateErr - not freeing the record.");
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u] regrecord_callback: Callback with error code mStatus_BadStateErr - not freeing the record.", request->request_id);
}
else
{
// unlink from list, free memory
registered_record_entry **ptr = &request->u.reg_recs;
while (*ptr && (*ptr) != re) ptr = &(*ptr)->next;
- if (!*ptr) { LogMsg("regrecord_callback - record not in list!"); return; }
+ if (!*ptr)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%u] regrecord_callback - record not in list!", request->request_id);
+ return;
+ }
*ptr = (*ptr)->next;
freeL("registered_record_entry AuthRecord regrecord_callback", re->rr);
freeL("registered_record_entry regrecord_callback", re);
@@ -996,14 +1164,21 @@ mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord *rr, mStatus result)
}
else
{
- if (re->external_advertise) LogMsg("regrecord_callback: external_advertise already set!");
+ if (re->external_advertise)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%u] regrecord_callback: external_advertise already set!", request->request_id);
+ }
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
if (callExternalHelpers(re->origInterfaceID, &rr->namestorage, request->flags))
{
- LogInfo("regrecord_callback: calling external_start_advertising_service");
- external_start_advertising_service(&rr->resrec, request->flags);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u] regrecord_callback: calling external_start_advertising_service", request->request_id);
+ external_start_advertising_service(&rr->resrec, request->flags, request->process_id);
re->external_advertise = mDNStrue;
}
+#endif
}
}
}
@@ -1012,14 +1187,11 @@ mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord *rr, mStatus result)
// This accounts for 2 places (connect_callback, request_callback)
mDNSlocal void set_peer_pid(request_state *request)
{
-#ifdef LOCAL_PEEREPID
- pid_t p = (pid_t) -1;
- socklen_t len = sizeof(p);
-#endif
-
request->pid_name[0] = '\0';
request->process_id = -1;
#ifdef LOCAL_PEEREPID
+ pid_t p = (pid_t) -1;
+ socklen_t len = sizeof(p);
if (request->sd < 0)
return;
// to extract the effective pid value
@@ -1044,7 +1216,9 @@ mDNSlocal void connection_termination(request_state *request)
// and terminate any subbordinate operations sharing this file descriptor
request_state **req = &all_requests;
- LogOperation("%3d: DNSServiceCreateConnection STOP PID[%d](%s)", request->sd, request->process_id, request->pid_name);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceCreateConnection STOP PID[%d](" PUB_S ")",
+ request->request_id, request->process_id, request->pid_name);
while (*req)
{
@@ -1056,6 +1230,15 @@ mDNSlocal void connection_termination(request_state *request)
if (tmp->replies) LogMsg("connection_termination ERROR How can subordinate req %p %d have replies queued?", tmp, tmp->sd);
abort_request(tmp);
*req = tmp->next;
+#if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
+ if (tmp->trust)
+ {
+ void * context = mdns_trust_get_context(tmp->trust);
+ mdns_trust_set_context(tmp->trust, NULL);
+ if (context) freeL("context/connection_termination", context);
+ mdns_trust_forget(&tmp->trust);
+ }
+#endif
freeL("request_state/connection_termination", tmp);
}
else
@@ -1065,13 +1248,18 @@ mDNSlocal void connection_termination(request_state *request)
while (request->u.reg_recs)
{
registered_record_entry *ptr = request->u.reg_recs;
- LogOperation("%3d: DNSServiceRegisterRecord(%u %s) STOP PID[%d](%s)", request->sd, ptr->key, RRDisplayString(&mDNSStorage, &ptr->rr->resrec), request->process_id, request->pid_name);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceRegisterRecord(0x%X, %d, " PRI_S ") STOP PID[%d](" PUB_S ")",
+ request->request_id, request->flags, request->interfaceIndex, RRDisplayString(&mDNSStorage, &ptr->rr->resrec), request->process_id,
+ request->pid_name);
request->u.reg_recs = request->u.reg_recs->next;
ptr->rr->RecordContext = NULL;
if (ptr->external_advertise)
{
ptr->external_advertise = mDNSfalse;
- external_stop_advertising_service(&ptr->rr->resrec, request->flags);
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+ external_stop_advertising_service(&ptr->rr->resrec, request->flags, request->process_id);
+#endif
}
LogMcastS(ptr->rr, request, reg_stop);
mDNS_Deregister(&mDNSStorage, ptr->rr); // Will free ptr->rr for us
@@ -1082,7 +1270,8 @@ mDNSlocal void connection_termination(request_state *request)
mDNSlocal void handle_cancel_request(request_state *request)
{
request_state **req = &all_requests;
- LogDebug("%3d: Cancel %08X %08X", request->sd, request->hdr.client_context.u32[1], request->hdr.client_context.u32[0]);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG, "[R%d] Cancel %08X %08X",
+ request->request_id, request->hdr.client_context.u32[1], request->hdr.client_context.u32[0]);
while (*req)
{
if ((*req)->primary == request &&
@@ -1093,6 +1282,15 @@ mDNSlocal void handle_cancel_request(request_state *request)
request_state *tmp = *req;
abort_request(tmp);
*req = tmp->next;
+#if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
+ if (tmp->trust)
+ {
+ void * context = mdns_trust_get_context(tmp->trust);
+ mdns_trust_set_context(tmp->trust, NULL);
+ if (context) freeL("context/handle_cancel_request", context);
+ mdns_trust_forget(&tmp->trust);
+ }
+#endif
freeL("request_state/handle_cancel_request", tmp);
}
else
@@ -1100,6 +1298,161 @@ mDNSlocal void handle_cancel_request(request_state *request)
}
}
+mDNSlocal mStatus _handle_regrecord_request_start(request_state *request, AuthRecord * rr)
+{
+ mStatus err;
+ registered_record_entry *re;
+ // Don't allow non-local domains to be regsitered as LocalOnly. Allowing this would permit
+ // clients to register records such as www.bigbank.com A w.x.y.z to redirect Safari.
+ if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly && !IsLocalDomain(rr->resrec.name) &&
+ rr->resrec.rrclass == kDNSClass_IN && (rr->resrec.rrtype == kDNSType_A || rr->resrec.rrtype == kDNSType_AAAA ||
+ rr->resrec.rrtype == kDNSType_CNAME))
+ {
+ freeL("AuthRecord/handle_regrecord_request", rr);
+ return (mStatus_BadParamErr);
+ }
+ // allocate registration entry, link into list
+ re = (registered_record_entry *) callocL("registered_record_entry", sizeof(*re));
+ if (!re) FatalError("ERROR: calloc");
+ re->key = request->hdr.reg_index;
+ re->rr = rr;
+ re->regrec_client_context = request->hdr.client_context;
+ re->request = request;
+ re->external_advertise = mDNSfalse;
+ rr->RecordContext = re;
+ rr->RecordCallback = regrecord_callback;
+
+ re->origInterfaceID = rr->resrec.InterfaceID;
+ if (rr->resrec.InterfaceID == mDNSInterface_P2P)
+ rr->resrec.InterfaceID = mDNSInterface_Any;
+#if 0
+ if (!AuthorizedDomain(request, rr->resrec.name, AutoRegistrationDomains)) return (mStatus_NoError);
+#endif
+ if (rr->resrec.rroriginalttl == 0)
+ rr->resrec.rroriginalttl = DefaultTTLforRRType(rr->resrec.rrtype);
+
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceRegisterRecord(0x%X, %d, " PRI_S ") START PID[%d](" PUB_S ")",
+ request->request_id, request->flags, request->interfaceIndex, RRDisplayString(&mDNSStorage, &rr->resrec), request->process_id,
+ request->pid_name);
+
+ err = mDNS_Register(&mDNSStorage, rr);
+ if (err)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceRegisterRecord(0x%X, %d," PRI_S ") ERROR (%d)",
+ request->request_id, request->flags, request->interfaceIndex, RRDisplayString(&mDNSStorage, &rr->resrec), err);
+ freeL("registered_record_entry", re);
+ freeL("registered_record_entry/AuthRecord", rr);
+ }
+ else
+ {
+ LogMcastS(rr, request, reg_start);
+ re->next = request->u.reg_recs;
+ request->u.reg_recs = re;
+ }
+ return err;
+}
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
+
+mDNSlocal void _return_regrecord_request_error(request_state *request, mStatus error)
+{
+ reply_state *rep;
+ if (GenerateNTDResponse(NULL, 0, request, &rep, reg_record_reply_op, 0, error) != mStatus_NoError)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "[R%u] DNSServiceRegisterRecord _return_regrecord_request_error: error(%d)", request->request_id, error);
+ }
+ else
+ {
+ append_reply(request, rep);
+ }
+}
+
+mDNSlocal mStatus _handle_regrecord_request_with_trust(request_state *request, AuthRecord * rr)
+{
+ mStatus err;
+ if (audit_token_to_pid(request->audit_token) == 0)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_WARNING, "[R%u] _handle_regrecord_request_with_trust: no audit token for pid(%s %d)", request->request_id, request->pid_name, request->process_id);
+ err = _handle_regrecord_request_start(request, rr);
+ }
+ else
+ {
+ const char *service_ptr = NULL;
+ char type_str[MAX_ESCAPED_DOMAIN_NAME] = "";
+ domainlabel name;
+ domainname type, domain;
+ bool good = DeconstructServiceName(rr->resrec.name, &name, &type, &domain);
+ if (good)
+ {
+ ConvertDomainNameToCString(&type, type_str);
+ service_ptr = type_str;
+ }
+
+ mdns_trust_flags_t flags = mdns_trust_flags_none;
+ mdns_trust_status_t status = mdns_trust_check_bonjour(request->audit_token, service_ptr, &flags);
+ switch (status)
+ {
+ case mdns_trust_status_denied:
+ case mdns_trust_status_pending:
+ {
+ mdns_trust_t trust = mdns_trust_create(request->audit_token, service_ptr, flags);
+ if (!trust)
+ {
+ freeL("AuthRecord/_handle_regrecord_request_with_trust", rr);
+ err = mStatus_NoMemoryErr;
+ goto exit;
+ }
+ mdns_trust_set_context(trust, rr);
+ mdns_trust_set_queue(trust, _get_trust_results_dispatch_queue());
+ mdns_trust_set_event_handler(trust, ^(mdns_trust_event_t event, mdns_trust_status_t update)
+ {
+ if (event == mdns_trust_event_result)
+ {
+ mStatus error = (update != mdns_trust_status_granted) ? mStatus_PolicyDenied : mStatus_NoError;
+ KQueueLock();
+ AuthRecord * _rr = mdns_trust_get_context(trust);
+ if (_rr)
+ {
+ if (!error)
+ {
+ mdns_trust_set_context(trust, NULL); // _handle_regrecord_request_start handles free
+ error = _handle_regrecord_request_start(request, _rr);
+ // No context means the request was canceled before we got here
+ }
+ if (error) // (not else if) Always check for error result
+ {
+ _return_regrecord_request_error(request, error);
+ }
+ }
+ KQueueUnlock("_handle_regrecord_request_with_trust");
+ }
+ });
+ request->trust = trust;
+ mdns_trust_activate(trust);
+ err = mStatus_NoError;
+ break;
+ }
+
+ case mdns_trust_status_no_entitlement:
+ err = mStatus_NoAuth;
+ break;
+
+ case mdns_trust_status_granted:
+ err = _handle_regrecord_request_start(request, rr);
+ break;
+
+ default:
+ err = mStatus_UnknownErr;
+ break;
+ }
+ }
+exit:
+ return err;
+}
+#endif // TRUST_ENFORCEMENT
+
mDNSlocal mStatus handle_regrecord_request(request_state *request)
{
mStatus err = mStatus_BadParamErr;
@@ -1111,53 +1464,19 @@ mDNSlocal mStatus handle_regrecord_request(request_state *request)
rr = read_rr_from_ipc_msg(request, 1, 1);
if (rr)
{
- registered_record_entry *re;
- // Don't allow non-local domains to be regsitered as LocalOnly. Allowing this would permit
- // clients to register records such as www.bigbank.com A w.x.y.z to redirect Safari.
- if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly && !IsLocalDomain(rr->resrec.name) &&
- rr->resrec.rrclass == kDNSClass_IN && (rr->resrec.rrtype == kDNSType_A || rr->resrec.rrtype == kDNSType_AAAA ||
- rr->resrec.rrtype == kDNSType_CNAME))
+#if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
+ if (os_feature_enabled(mDNSResponder, bonjour_privacy) &&
+ IsLocalDomain(rr->resrec.name))
{
- freeL("AuthRecord/handle_regrecord_request", rr);
- return (mStatus_BadParamErr);
- }
- // allocate registration entry, link into list
- re = mallocL("registered_record_entry", sizeof(registered_record_entry));
- if (!re)
- FatalError("ERROR: malloc");
- re->key = request->hdr.reg_index;
- re->rr = rr;
- re->regrec_client_context = request->hdr.client_context;
- re->request = request;
- re->external_advertise = mDNSfalse;
- rr->RecordContext = re;
- rr->RecordCallback = regrecord_callback;
-
- re->origInterfaceID = rr->resrec.InterfaceID;
- if (rr->resrec.InterfaceID == mDNSInterface_P2P)
- rr->resrec.InterfaceID = mDNSInterface_Any;
-#if 0
- if (!AuthorizedDomain(request, rr->resrec.name, AutoRegistrationDomains)) return (mStatus_NoError);
-#endif
- if (rr->resrec.rroriginalttl == 0)
- rr->resrec.rroriginalttl = DefaultTTLforRRType(rr->resrec.rrtype);
-
- LogOperation("%3d: DNSServiceRegisterRecord(%u %s) START PID[%d](%s)", request->sd, re->key, RRDisplayString(&mDNSStorage, &rr->resrec),
- request->process_id, request->pid_name);
-
- err = mDNS_Register(&mDNSStorage, rr);
- if (err)
- {
- LogOperation("%3d: DNSServiceRegisterRecord(%u %s) ERROR (%d)", request->sd, re->key, RRDisplayString(&mDNSStorage, &rr->resrec), err);
- freeL("registered_record_entry", re);
- freeL("registered_record_entry/AuthRecord", rr);
+ err = _handle_regrecord_request_with_trust(request, rr);
}
else
{
- LogMcastS(rr, request, reg_start);
- re->next = request->u.reg_recs;
- request->u.reg_recs = re;
+ err = _handle_regrecord_request_start(request, rr);
}
+#else
+ err = _handle_regrecord_request_start(request, rr);
+#endif
}
return(err);
}
@@ -1176,10 +1495,13 @@ mDNSlocal void regservice_termination_callback(request_state *request)
service_instance *p = request->u.servicereg.instances;
request->u.servicereg.instances = request->u.servicereg.instances->next;
// only safe to free memory if registration is not valid, i.e. deregister fails (which invalidates p)
- LogOperation("%3d: DNSServiceRegister(%##s, %u) STOP PID[%d](%s)", request->sd, p->srs.RR_SRV.resrec.name->c,
- mDNSVal16(p->srs.RR_SRV.resrec.rdata->u.srv.port), request->process_id, request->pid_name);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%d] DNSServiceRegister(" PRI_DM_NAME ", %u) STOP PID[%d](" PUB_S ")",
+ request->request_id, DM_NAME_PARAM(p->srs.RR_SRV.resrec.name),
+ mDNSVal16(p->srs.RR_SRV.resrec.rdata->u.srv.port), request->process_id, request->pid_name);
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
external_stop_advertising_helper(p);
+#endif
// Clear backpointer *before* calling mDNS_DeregisterService/unlink_and_free_service_instance
// We don't need unlink_and_free_service_instance to cut its element from the list, because we're already advancing
@@ -1217,19 +1539,29 @@ mDNSlocal request_state *LocateSubordinateRequest(request_state *request)
return(request);
}
-mDNSlocal mStatus add_record_to_service(request_state *request, service_instance *instance, mDNSu16 rrtype, mDNSu16 rdlen, const char *rdata, mDNSu32 ttl)
+mDNSlocal mStatus add_record_to_service(request_state *request, service_instance *instance, mDNSu16 rrtype, mDNSu16 rdlen,
+ const mDNSu8 *const rdata, mDNSu32 ttl)
{
ServiceRecordSet *srs = &instance->srs;
mStatus result;
- size_t size = rdlen > sizeof(RDataBody) ? rdlen : sizeof(RDataBody);
- ExtraResourceRecord *extra = mallocL("ExtraResourceRecord", sizeof(*extra) - sizeof(RDataBody) + size);
- if (!extra) { my_perror("ERROR: malloc"); return mStatus_NoMemoryErr; }
+ const size_t rdcapacity = (rdlen > sizeof(RDataBody2)) ? rdlen : sizeof(RDataBody2);
+ ExtraResourceRecord *extra = (ExtraResourceRecord *)callocL("ExtraResourceRecord", sizeof(*extra) - sizeof(RDataBody) + rdcapacity);
+ if (!extra) { my_perror("ERROR: calloc"); return mStatus_NoMemoryErr; }
- mDNSPlatformMemZero(extra, sizeof(ExtraResourceRecord)); // OK if oversized rdata not zero'd
extra->r.resrec.rrtype = rrtype;
- extra->r.rdatastorage.MaxRDLength = (mDNSu16) size;
+ extra->r.resrec.rdata = &extra->r.rdatastorage;
+ extra->r.resrec.rdata->MaxRDLength = (mDNSu16)rdcapacity;
extra->r.resrec.rdlength = rdlen;
- mDNSPlatformMemCopy(&extra->r.rdatastorage.u.data, rdata, rdlen);
+ if (!SetRData(mDNSNULL, rdata, rdata + rdlen, &extra->r.resrec, rdlen))
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[R%u] read_rr_from_ipc_msg: SetRData failed for " PRI_DM_NAME " (" PUB_S ")",
+ request->request_id, DM_NAME_PARAM(request->u.servicereg.instances ?
+ request->u.servicereg.instances->srs.RR_SRV.resrec.name : mDNSNULL), DNSTypeName(rrtype));
+ freeL("ExtraResourceRecord/add_record_to_service", extra);
+ return mStatus_BadParamErr;
+ }
+ SetNewRData(&extra->r.resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
// use InterfaceID value from DNSServiceRegister() call that created the original service
extra->r.resrec.InterfaceID = request->u.servicereg.InterfaceID;
@@ -1242,12 +1574,14 @@ mDNSlocal mStatus add_record_to_service(request_state *request, service_instance
LogMcastS(&srs->RR_PTR, request, reg_start);
extra->ClientID = request->hdr.reg_index;
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
if ( instance->external_advertise
&& callExternalHelpers(request->u.servicereg.InterfaceID, &instance->domain, request->flags))
{
LogInfo("add_record_to_service: calling external_start_advertising_service");
- external_start_advertising_service(&extra->r.resrec, request->flags);
+ external_start_advertising_service(&extra->r.resrec, request->flags, request->process_id);
}
+#endif
return result;
}
@@ -1258,27 +1592,41 @@ mDNSlocal mStatus handle_add_request(request_state *request)
DNSServiceFlags flags = get_flags (&request->msgptr, request->msgend);
mDNSu16 rrtype = get_uint16(&request->msgptr, request->msgend);
mDNSu16 rdlen = get_uint16(&request->msgptr, request->msgend);
- const char *rdata = get_rdata (&request->msgptr, request->msgend, rdlen);
+ const mDNSu8 *const rdata = (const mDNSu8 *)get_rdata(&request->msgptr, request->msgend, rdlen);
mDNSu32 ttl = get_uint32(&request->msgptr, request->msgend);
if (!ttl) ttl = DefaultTTLforRRType(rrtype);
(void)flags; // Unused
- if (!request->msgptr) { LogMsg("%3d: DNSServiceAddRecord(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
+ if (!request->msgptr)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%d] DNSServiceAddRecord(unreadable parameters)", request->request_id);
+ return(mStatus_BadParamErr);
+ }
// If this is a shared connection, check if the operation actually applies to a subordinate request_state object
if (request->terminate == connection_termination) request = LocateSubordinateRequest(request);
if (request->terminate != regservice_termination_callback)
- { LogMsg("%3d: DNSServiceAddRecord(not a registered service ref)", request->sd); return(mStatus_BadParamErr); }
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%d] DNSServiceAddRecord(not a registered service ref)", request->request_id);
+ return(mStatus_BadParamErr);
+ }
// For a service registered with zero port, don't allow adding records. This mostly happens due to a bug
// in the application. See radar://9165807.
if (mDNSIPPortIsZero(request->u.servicereg.port))
- { LogMsg("%3d: DNSServiceAddRecord: adding record to a service registered with zero port", request->sd); return(mStatus_BadParamErr); }
-
- LogOperation("%3d: DNSServiceAddRecord(%X, %##s, %s, %d) PID[%d](%s)", request->sd, flags,
- (request->u.servicereg.instances) ? request->u.servicereg.instances->srs.RR_SRV.resrec.name->c : NULL, DNSTypeName(rrtype), rdlen,
- request->process_id, request->pid_name);
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%d] DNSServiceAddRecord: adding record to a service registered with zero port", request->request_id);
+ return(mStatus_BadParamErr);
+ }
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceAddRecord(%X, " PRI_DM_NAME ", " PUB_S ", %d) PID[%d](" PUB_S ")",
+ request->request_id, flags,
+ DM_NAME_PARAM((request->u.servicereg.instances) ? (request->u.servicereg.instances->srs.RR_SRV.resrec.name) : mDNSNULL),
+ DNSTypeName(rrtype), rdlen, request->process_id, request->pid_name);
for (i = request->u.servicereg.instances; i; i = i->next)
{
@@ -1307,36 +1655,55 @@ mDNSlocal void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd
if (external_advertise)
{
ResourceRecord ext = rr->resrec;
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
DNSServiceFlags flags = deriveD2DFlagsFromAuthRecType(rr->ARType);
+#endif
if (ext.rdlength == oldrdlen && mDNSPlatformMemSame(&ext.rdata->u, &oldrd->u, oldrdlen)) goto exit;
SetNewRData(&ext, oldrd, oldrdlen);
- external_stop_advertising_service(&ext, flags);
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+ external_stop_advertising_service(&ext, flags, 0);
LogInfo("update_callback: calling external_start_advertising_service");
- external_start_advertising_service(&rr->resrec, flags);
+ external_start_advertising_service(&rr->resrec, flags, 0);
+#endif
}
exit:
if (oldrd != &rr->rdatastorage) freeL("RData/update_callback", oldrd);
}
-mDNSlocal mStatus update_record(AuthRecord *rr, mDNSu16 rdlen, const char *rdata, mDNSu32 ttl, const mDNSBool *const external_advertise)
+mDNSlocal mStatus update_record(AuthRecord *ar, mDNSu16 rdlen, const mDNSu8 *const rdata, mDNSu32 ttl,
+ const mDNSBool *const external_advertise, const mDNSu32 request_id)
{
+ ResourceRecord rr;
mStatus result;
- const size_t rdsize = rdlen > sizeof(RDataBody) ? rdlen : sizeof(RDataBody);
- RData *newrd = mallocL("RData/update_record", sizeof(RData) - sizeof(RDataBody) + rdsize);
- if (!newrd) FatalError("ERROR: malloc");
- newrd->MaxRDLength = (mDNSu16) rdsize;
- mDNSPlatformMemCopy(&newrd->u, rdata, rdlen);
-
+ const size_t rdcapacity = (rdlen > sizeof(RDataBody2)) ? rdlen : sizeof(RDataBody2);
+ RData *newrd = (RData *) callocL("RData/update_record", sizeof(*newrd) - sizeof(RDataBody) + rdcapacity);
+ if (!newrd) FatalError("ERROR: calloc");
+ mDNSPlatformMemZero(&rr, (mDNSu32)sizeof(rr));
+ rr.name = ar->resrec.name;
+ rr.rrtype = ar->resrec.rrtype;
+ rr.rrclass = ar->resrec.rrclass;
+ rr.rdata = newrd;
+ rr.rdata->MaxRDLength = (mDNSu16)rdcapacity;
+ rr.rdlength = rdlen;
+ if (!SetRData(mDNSNULL, rdata, rdata + rdlen, &rr, rdlen))
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[R%u] update_record: SetRData failed for " PRI_DM_NAME " (" PUB_S ")",
+ request_id, DM_NAME_PARAM(rr.name), DNSTypeName(rr.rrtype));
+ freeL("RData/update_record", newrd);
+ return mStatus_BadParamErr;
+ }
+ rdlen = GetRDLength(&rr, mDNSfalse);
// BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
// since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
// Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
- if (rr->resrec.rrtype == kDNSType_TXT && rdlen == 0) { rdlen = 1; newrd->u.txt.c[0] = 0; }
+ if (ar->resrec.rrtype == kDNSType_TXT && rdlen == 0) { rdlen = 1; newrd->u.txt.c[0] = 0; }
- if (external_advertise) rr->UpdateContext = (void *)external_advertise;
+ if (external_advertise) ar->UpdateContext = (void *)external_advertise;
- result = mDNS_Update(&mDNSStorage, rr, ttl, rdlen, newrd, update_callback);
- if (result) { LogMsg("update_record: Error %d for %s", (int)result, ARDisplayString(&mDNSStorage, rr)); freeL("RData/update_record", newrd); }
+ result = mDNS_Update(&mDNSStorage, ar, ttl, rdlen, newrd, update_callback);
+ if (result) { LogMsg("update_record: Error %d for %s", (int)result, ARDisplayString(&mDNSStorage, ar)); freeL("RData/update_record", newrd); }
return result;
}
@@ -1350,11 +1717,16 @@ mDNSlocal mStatus handle_update_request(request_state *request)
// get the message data
DNSServiceFlags flags = get_flags (&request->msgptr, request->msgend); // flags unused
mDNSu16 rdlen = get_uint16(&request->msgptr, request->msgend);
- const char *rdata = get_rdata (&request->msgptr, request->msgend, rdlen);
+ const mDNSu8 *const rdata = (const mDNSu8 *)get_rdata(&request->msgptr, request->msgend, rdlen);
mDNSu32 ttl = get_uint32(&request->msgptr, request->msgend);
(void)flags; // Unused
- if (!request->msgptr) { LogMsg("%3d: DNSServiceUpdateRecord(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
+ if (!request->msgptr)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%d] DNSServiceUpdateRecord(unreadable parameters)", request->request_id);
+ return(mStatus_BadParamErr);
+ }
// If this is a shared connection, check if the operation actually applies to a subordinate request_state object
if (request->terminate == connection_termination) request = LocateSubordinateRequest(request);
@@ -1367,10 +1739,12 @@ mDNSlocal mStatus handle_update_request(request_state *request)
{
if (reptr->key == hdr->reg_index)
{
- result = update_record(reptr->rr, rdlen, rdata, ttl, &reptr->external_advertise);
- LogOperation("%3d: DNSServiceUpdateRecord(%##s, %s) PID[%d](%s)",
- request->sd, reptr->rr->resrec.name->c, reptr->rr ? DNSTypeName(reptr->rr->resrec.rrtype) : "<NONE>",
- request->process_id, request->pid_name);
+ result = update_record(reptr->rr, rdlen, rdata, ttl, &reptr->external_advertise, request->request_id);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%d] DNSServiceUpdateRecord(" PRI_DM_NAME ", " PUB_S ") PID[%d](" PUB_S ")",
+ request->request_id, DM_NAME_PARAM(reptr->rr->resrec.name),
+ reptr->rr ? DNSTypeName(reptr->rr->resrec.rrtype) : "<NONE>",
+ request->process_id, request->pid_name);
goto end;
}
}
@@ -1379,11 +1753,19 @@ mDNSlocal mStatus handle_update_request(request_state *request)
}
if (request->terminate != regservice_termination_callback)
- { LogMsg("%3d: DNSServiceUpdateRecord(not a registered service ref)", request->sd); return(mStatus_BadParamErr); }
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%d] DNSServiceUpdateRecord(not a registered service ref)", request->request_id);
+ return(mStatus_BadParamErr);
+ }
// For a service registered with zero port, only SRV record is initialized. Don't allow any updates.
if (mDNSIPPortIsZero(request->u.servicereg.port))
- { LogMsg("%3d: DNSServiceUpdateRecord: updating the record of a service registered with zero port", request->sd); return(mStatus_BadParamErr); }
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%d] DNSServiceUpdateRecord: updating the record of a service registered with zero port", request->request_id);
+ return(mStatus_BadParamErr);
+ }
// update the saved off TXT data for the service
if (hdr->reg_index == TXT_RECORD_INDEX)
@@ -1411,7 +1793,7 @@ mDNSlocal mStatus handle_update_request(request_state *request)
}
if (!rr) { result = mStatus_BadReferenceErr; goto end; }
- result = update_record(rr, rdlen, rdata, ttl, &i->external_advertise);
+ result = update_record(rr, rdlen, rdata, ttl, &i->external_advertise, request->request_id);
if (result && i->default_local) goto end;
else result = mStatus_NoError; // suppress non-local default errors
}
@@ -1442,7 +1824,9 @@ mDNSlocal mStatus remove_record(request_state *request)
e->rr->RecordContext = NULL;
if (e->external_advertise)
{
- external_stop_advertising_service(&e->rr->resrec, request->flags);
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+ external_stop_advertising_service(&e->rr->resrec, request->flags, request->process_id);
+#endif
e->external_advertise = mDNSfalse;
}
LogMcastS(e->rr, request, reg_stop);
@@ -1466,7 +1850,12 @@ mDNSlocal mStatus remove_extra(const request_state *const request, service_insta
if (ptr->ClientID == request->hdr.reg_index) // found match
{
*rrtype = ptr->r.resrec.rrtype;
- if (serv->external_advertise) external_stop_advertising_service(&ptr->r.resrec, request->flags);
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+ if (serv->external_advertise)
+ {
+ external_stop_advertising_service(&ptr->r.resrec, request->flags, request->process_id);
+ }
+#endif
err = mDNS_RemoveRecordFromService(&mDNSStorage, &serv->srs, ptr, FreeExtraRR, ptr);
break;
}
@@ -1479,7 +1868,12 @@ mDNSlocal mStatus handle_removerecord_request(request_state *request)
mStatus err = mStatus_BadReferenceErr;
get_flags(&request->msgptr, request->msgend); // flags unused
- if (!request->msgptr) { LogMsg("%3d: DNSServiceRemoveRecord(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
+ if (!request->msgptr)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%d] DNSServiceRemoveRecord(unreadable parameters)", request->request_id);
+ return(mStatus_BadParamErr);
+ }
// If this is a shared connection, check if the operation actually applies to a subordinate request_state object
if (request->terminate == connection_termination) request = LocateSubordinateRequest(request);
@@ -1487,14 +1881,19 @@ mDNSlocal mStatus handle_removerecord_request(request_state *request)
if (request->terminate == connection_termination)
err = remove_record(request); // remove individually registered record
else if (request->terminate != regservice_termination_callback)
- { LogMsg("%3d: DNSServiceRemoveRecord(not a registered service ref)", request->sd); return(mStatus_BadParamErr); }
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%d] DNSServiceRemoveRecord(not a registered service ref)", request->request_id);
+ return(mStatus_BadParamErr);
+ }
else
{
service_instance *i;
mDNSu16 rrtype = 0;
- LogOperation("%3d: DNSServiceRemoveRecord(%##s, %s) PID[%d](%s)", request->sd,
- (request->u.servicereg.instances) ? request->u.servicereg.instances->srs.RR_SRV.resrec.name->c : NULL,
- rrtype ? DNSTypeName(rrtype) : "<NONE>", request->process_id, request->pid_name);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%d] DNSServiceRemoveRecord(" PRI_DM_NAME ", " PUB_S ") PID[%d](" PUB_S ")",
+ request->request_id,
+ DM_NAME_PARAM((request->u.servicereg.instances) ? (request->u.servicereg.instances->srs.RR_SRV.resrec.name) : mDNSNULL),
+ rrtype ? DNSTypeName(rrtype) : "<NONE>", request->process_id, request->pid_name);
for (i = request->u.servicereg.instances; i; i = i->next)
{
err = remove_extra(request, i, &rrtype);
@@ -1509,7 +1908,7 @@ mDNSlocal mStatus handle_removerecord_request(request_state *request)
// If there's a comma followed by another character,
// FindFirstSubType overwrites the comma with a nul and returns the pointer to the next character.
// Otherwise, it returns a pointer to the final nul at the end of the string
-mDNSlocal char *FindFirstSubType(char *p, char **AnonData)
+mDNSlocal char *FindFirstSubType(char *p)
{
while (*p)
{
@@ -1522,11 +1921,6 @@ mDNSlocal char *FindFirstSubType(char *p, char **AnonData)
*p++ = 0;
return(p);
}
- else if (p[0] == ':' && p[1])
- {
- *p++ = 0;
- *AnonData = p;
- }
else
{
p++;
@@ -1558,10 +1952,10 @@ mDNSlocal char *FindNextSubType(char *p)
}
// Returns -1 if illegal subtype found
-mDNSexport mDNSs32 ChopSubTypes(char *regtype, char **AnonData)
+mDNSlocal mDNSs32 ChopSubTypes(char *regtype)
{
mDNSs32 NumSubTypes = 0;
- char *stp = FindFirstSubType(regtype, AnonData);
+ char *stp = FindFirstSubType(regtype);
while (stp && *stp) // If we found a comma...
{
if (*stp == ',') return(-1);
@@ -1572,65 +1966,26 @@ mDNSexport mDNSs32 ChopSubTypes(char *regtype, char **AnonData)
return(NumSubTypes);
}
-mDNSexport AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p, char **AnonData)
+mDNSlocal AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p)
{
AuthRecord *st = mDNSNULL;
- //
- // "p" is pointing at the regtype e.g., _http._tcp followed by ":<AnonData>" indicated
- // by AnonData being non-NULL which is in turn follwed by ",<SubTypes>" indicated by
- // NumSubTypes being non-zero. We need to skip the initial regtype to get to the actual
- // data that we want. When we come here, ChopSubTypes has null terminated like this e.g.,
- //
- // _http._tcp<NULL><AnonData><NULL><SubType1><NULL><SubType2><NULL> etc.
- //
- // 1. If we have Anonymous data and subtypes, skip the regtype (e.g., "_http._tcp")
- // to get the AnonData and then skip the AnonData to get to the SubType.
- //
- // 2. If we have only SubTypes, skip the regtype to get to the SubType data.
- //
- // 3. If we have only AnonData, skip the regtype to get to the AnonData.
- //
- // 4. If we don't have AnonData or NumStypes, it is a noop.
- //
- if (AnonData)
- {
- int len;
-
- // Skip the regtype
- while (*p) p++;
- p++;
-
- len = strlen(p) + 1;
- *AnonData = mallocL("Anonymous", len);
- if (!(*AnonData))
- {
- return (mDNSNULL);
- }
- mDNSPlatformMemCopy(*AnonData, p, len);
- }
if (NumSubTypes)
{
mDNSs32 i;
- st = mallocL("ServiceSubTypes", NumSubTypes * sizeof(AuthRecord));
+ st = (AuthRecord *) callocL("ServiceSubTypes", NumSubTypes * sizeof(AuthRecord));
if (!st) return(mDNSNULL);
for (i = 0; i < NumSubTypes; i++)
{
mDNS_SetupResourceRecord(&st[i], mDNSNULL, mDNSInterface_Any, kDNSQType_ANY, kStandardTTL, 0, AuthRecordAny, mDNSNULL, mDNSNULL);
- // First time through we skip the regtype or AnonData. Subsequently, the
- // previous subtype.
while (*p) p++;
p++;
if (!MakeDomainNameFromDNSNameString(&st[i].namestorage, p))
{
freeL("ServiceSubTypes", st);
- if (AnonData && *AnonData)
- freeL("AnonymousData", *AnonData);
return(mDNSNULL);
}
}
}
- // If NumSubTypes is zero and AnonData is non-NULL, we still return NULL but AnonData has been
- // initialized. The caller knows how to handle this.
return(st);
}
@@ -1659,8 +2014,8 @@ mDNSlocal mStatus register_service_instance(request_state *request, const domain
}
}
- instance = mallocL("service_instance", sizeof(*instance) + extra_size);
- if (!instance) { my_perror("ERROR: malloc"); return mStatus_NoMemoryErr; }
+ instance = (service_instance *) callocL("service_instance", sizeof(*instance) + extra_size);
+ if (!instance) { my_perror("ERROR: calloc"); return mStatus_NoMemoryErr; }
instance->next = mDNSNULL;
instance->request = request;
@@ -1670,18 +2025,7 @@ mDNSlocal mStatus register_service_instance(request_state *request, const domain
instance->external_advertise = mDNSfalse;
AssignDomainName(&instance->domain, domain);
- instance->srs.AnonData = mDNSNULL;
- if (!request->u.servicereg.AnonData)
- {
- instance->subtypes = AllocateSubTypes(request->u.servicereg.num_subtypes, request->u.servicereg.type_as_string, mDNSNULL);
- }
- else
- {
- char *AnonData = mDNSNULL;
- instance->subtypes = AllocateSubTypes(request->u.servicereg.num_subtypes, request->u.servicereg.type_as_string, &AnonData);
- if (AnonData)
- instance->srs.AnonData = (const mDNSu8 *)AnonData;
- }
+ instance->subtypes = AllocateSubTypes(request->u.servicereg.num_subtypes, request->u.servicereg.type_as_string);
if (request->u.servicereg.num_subtypes && !instance->subtypes)
{
@@ -1774,80 +2118,163 @@ mDNSlocal void udsserver_default_reg_domain_changed(const DNameListElem *const d
}
}
-// Don't allow normal and anonymous registration to coexist.
-mDNSlocal mDNSBool CheckForMixedRegistrations(domainname *regtype, domainname *domain, mDNSBool AnonData)
+// Returns true if the interfaceIndex value matches one of the pre-defined
+// special values listed in the switch statement below.
+mDNSlocal mDNSBool PreDefinedInterfaceIndex(mDNSu32 interfaceIndex)
{
- request_state *request;
-
- // We only care about local domains where the anonymous extension is
- // implemented.
- if (!SameDomainName(domain, (const domainname *) "\x5" "local"))
+ switch(interfaceIndex)
{
- return mDNStrue;
+ case kDNSServiceInterfaceIndexAny:
+ case kDNSServiceInterfaceIndexLocalOnly:
+ case kDNSServiceInterfaceIndexUnicast:
+ case kDNSServiceInterfaceIndexP2P:
+ case kDNSServiceInterfaceIndexBLE:
+ return mDNStrue;
+ default:
+ return mDNSfalse;
}
+}
- for (request = all_requests; request; request = request->next)
+mDNSlocal mStatus _handle_regservice_request_start(request_state *request, const domainname * const d)
+{
+ mStatus err;
+
+ request->terminate = regservice_termination_callback;
+ err = register_service_instance(request, d);
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
+ ++curr_num_regservices;
+ if (curr_num_regservices > max_num_regservices)
+ max_num_regservices = curr_num_regservices;
+#endif
+
+#if 0
+ err = AuthorizedDomain(request, d, AutoRegistrationDomains) ? register_service_instance(request, d) : mStatus_NoError;
+#endif
+ if (!err)
{
- service_instance *ptr;
+ if (request->u.servicereg.autoname) UpdateDeviceInfoRecord(&mDNSStorage);
- if (request->terminate != regservice_termination_callback) continue;
- for (ptr = request->u.servicereg.instances; ptr ; ptr = ptr->next)
+ if (request->u.servicereg.default_domain)
{
- if (!SameDomainName(&ptr->domain, (const domainname *)"\x5" "local") ||
- !SameDomainName(&request->u.servicereg.type, regtype))
- {
- continue;
- }
+ DNameListElem *ptr;
+ // Note that we don't report errors for non-local, non-explicit domains
+ for (ptr = AutoRegistrationDomains; ptr; ptr = ptr->next)
+ if (!ptr->uid || SystemUID(request->uid) || request->uid == ptr->uid)
+ register_service_instance(request, &ptr->name);
+ }
+ }
+ return err;
+}
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
+
+mDNSlocal void _return_regservice_request_error(request_state *request, mStatus error)
+{
+ if (request->u.servicereg.txtdata)
+ {
+ freeL("service_info txtdata", request->u.servicereg.txtdata);
+ request->u.servicereg.txtdata = NULL;
+ }
+
+ reply_state *rep;
+ if (GenerateNTDResponse(NULL, 0, request, &rep, reg_service_reply_op, 0, error) != mStatus_NoError)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "[R%u] DNSServiceRegister _return_regservice_request_error: error(%d)", request->request_id, error);
+ }
+ else
+ {
+ append_reply(request, rep);
+ }
+}
- // If we are about to register a anonymous registraion, we dont't want to
- // allow the regular ones and vice versa.
- if (AnonData)
+mDNSlocal mStatus _handle_regservice_request_with_trust(request_state *request, const domainname * const d)
+{
+ mStatus err;
+ if (audit_token_to_pid(request->audit_token) == 0)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_WARNING, "[R%u] _handle_regservice_request_with_trust: no audit token for pid(%s %d)", request->request_id, request->pid_name, request->process_id);
+ err = _handle_regservice_request_start(request, d);
+ }
+ else
+ {
+ mdns_trust_flags_t flags = mdns_trust_flags_none;
+ mdns_trust_status_t status = mdns_trust_check_register_service(request->audit_token, request->u.servicereg.type_as_string, &flags);
+ switch (status) {
+ case mdns_trust_status_denied:
+ case mdns_trust_status_pending:
{
- if (!ptr->srs.AnonData)
+ mdns_trust_t trust = mdns_trust_create(request->audit_token, request->u.servicereg.type_as_string, flags);
+ if (!trust)
{
- LogMsg("CheckForMixedRegistrations: Normal registration already exists for %##s", regtype->c);
- return mDNSfalse;
+ err = mStatus_NoMemoryErr;
+ goto exit;
}
- }
- else
- {
- // Allow multiple regular registrations
- if (ptr->srs.AnonData)
+ void * context = mallocL("context/_handle_regservice_request_with_trust", sizeof(domainname));
+ if (!context)
{
- LogMsg("CheckForMixedRegistrations: Anonymous registration already exists for %##s", regtype->c);
- return mDNSfalse;
+ my_perror("ERROR: mallocL context/_handle_regservice_request_with_trust");
+ mdns_release(trust);
+ err = mStatus_NoMemoryErr;
+ goto exit;
}
+ memcpy(context, d, sizeof(domainname));
+ mdns_trust_set_context(trust, context);
+
+ mdns_trust_set_queue(trust, _get_trust_results_dispatch_queue());
+ mdns_trust_set_event_handler(trust, ^(mdns_trust_event_t event, mdns_trust_status_t update)
+ {
+ if (event == mdns_trust_event_result)
+ {
+ mStatus error = (update != mdns_trust_status_granted) ? mStatus_PolicyDenied : mStatus_NoError;
+ KQueueLock();
+ const domainname * _d = mdns_trust_get_context(trust);
+ if (_d)
+ {
+ if (!error)
+ {
+ error = _handle_regservice_request_start(request, _d);
+ // No context means the request was canceled before we got here
+ }
+ if (error) // (not else if) Always check for error result
+ {
+ _return_regservice_request_error(request, error);
+ }
+ }
+ KQueueUnlock("_register_service_instance_with_trust");
+ }
+ });
+ request->trust = trust;
+ mdns_trust_activate(trust);
+ err = mStatus_NoError;
+ break;
}
- }
- }
- return mDNStrue;
-}
-// Returns true if the interfaceIndex value matches one of the pre-defined
-// special values listed in the switch statement below.
-mDNSlocal mDNSBool PreDefinedInterfaceIndex(mDNSu32 interfaceIndex)
-{
- switch(interfaceIndex)
- {
- case kDNSServiceInterfaceIndexAny:
- case kDNSServiceInterfaceIndexLocalOnly:
- case kDNSServiceInterfaceIndexUnicast:
- case kDNSServiceInterfaceIndexP2P:
- case kDNSServiceInterfaceIndexBLE:
- return mDNStrue;
- default:
- return mDNSfalse;
+ case mdns_trust_status_no_entitlement:
+ err = mStatus_NoAuth;
+ break;
+
+ case mdns_trust_status_granted:
+ err = _handle_regservice_request_start(request, d);
+ break;
+
+ default:
+ err = mStatus_UnknownErr;
+ break;
+ }
}
+exit:
+ return err;
}
+#endif // TRUST_ENFORCEMENT
mDNSlocal mStatus handle_regservice_request(request_state *request)
{
char name[256]; // Lots of spare space for extra-long names that we'll auto-truncate down to 63 bytes
char domain[MAX_ESCAPED_DOMAIN_NAME], host[MAX_ESCAPED_DOMAIN_NAME];
- char type_as_string[MAX_ESCAPED_DOMAIN_NAME];
+ char type_as_string[MAX_ESCAPED_DOMAIN_NAME]; // Note that this service type may include a trailing list of subtypes
domainname d, srv;
mStatus err;
- char *AnonData = mDNSNULL;
const char *msgTXTData;
DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
@@ -1882,10 +2309,10 @@ mDNSlocal mStatus handle_regservice_request(request_state *request)
LogInfo("handle_regservice_request: registration pending for interface index %d", interfaceIndex);
}
- if (get_string(&request->msgptr, request->msgend, name, sizeof(name)) < 0 ||
- get_string(&request->msgptr, request->msgend, type_as_string, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
- get_string(&request->msgptr, request->msgend, domain, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
- get_string(&request->msgptr, request->msgend, host, MAX_ESCAPED_DOMAIN_NAME) < 0)
+ if (get_string(&request->msgptr, request->msgend, name, sizeof(name )) < 0 ||
+ get_string(&request->msgptr, request->msgend, type_as_string, sizeof(type_as_string)) < 0 ||
+ get_string(&request->msgptr, request->msgend, domain, sizeof(domain )) < 0 ||
+ get_string(&request->msgptr, request->msgend, host, sizeof(host )) < 0)
{ LogMsg("ERROR: handle_regservice_request - Couldn't read name/regtype/domain"); return(mStatus_BadParamErr); }
request->flags = flags;
@@ -1916,26 +2343,12 @@ mDNSlocal mStatus handle_regservice_request(request_state *request)
}
// Check for sub-types after the service type
- request->u.servicereg.num_subtypes = ChopSubTypes(request->u.servicereg.type_as_string, &AnonData); // Note: Modifies regtype string to remove trailing subtypes
+ request->u.servicereg.num_subtypes = ChopSubTypes(request->u.servicereg.type_as_string); // Note: Modifies regtype string to remove trailing subtypes
if (request->u.servicereg.num_subtypes < 0)
{
LogMsg("ERROR: handle_regservice_request - ChopSubTypes failed %s", request->u.servicereg.type_as_string);
goto bad_param;
}
- if (AnonData)
- {
- int AnonDataLen = strlen(AnonData);
- if (AnonDataLen > MAX_ANONYMOUS_DATA)
- {
- LogMsg("ERROR: handle_regservice_request: AnonDataLen %d", AnonDataLen);
- goto bad_param;
- }
- request->u.servicereg.AnonData = mDNStrue;
- }
- else
- {
- request->u.servicereg.AnonData = mDNSfalse;
- }
// Don't try to construct "domainname t" until *after* ChopSubTypes has worked its magic
if (!*request->u.servicereg.type_as_string || !MakeDomainNameFromDNSNameString(&request->u.servicereg.type, request->u.servicereg.type_as_string))
@@ -1971,9 +2384,6 @@ mDNSlocal mStatus handle_regservice_request(request_state *request)
MakeDomainNameFromDNSNameString(&d, "local.");
}
- // We don't allow the anonymous and the regular ones to coexist
- if (!CheckForMixedRegistrations(&request->u.servicereg.type, &d, request->u.servicereg.AnonData)) { goto bad_param; }
-
if (!ConstructServiceName(&srv, &request->u.servicereg.name, &request->u.servicereg.type, &d))
{
LogMsg("ERROR: handle_regservice_request - Couldn't ConstructServiceName from, “%#s” “%##s” “%##s”",
@@ -2005,42 +2415,37 @@ mDNSlocal mStatus handle_regservice_request(request_state *request)
}
#endif // APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
- LogOperation("%3d: DNSServiceRegister(%X, %d, \"%s\", \"%s\", \"%s\", \"%s\", %u) START PID[%d](%s)",
- request->sd, request->flags, interfaceIndex, name, request->u.servicereg.type_as_string, domain, host,
- mDNSVal16(request->u.servicereg.port), request->process_id, request->pid_name);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceRegister(%X, %d, \"" PRI_S "\", \"" PRI_S "\", \"" PRI_S "\", \"" PRI_S "\", %u) START PID[%d](" PUB_S ")",
+ request->request_id, request->flags, interfaceIndex, name, request->u.servicereg.type_as_string, domain, host,
+ mDNSVal16(request->u.servicereg.port), request->process_id, request->pid_name);
// We need to unconditionally set request->terminate, because even if we didn't successfully
// start any registrations right now, subsequent configuration changes may cause successful
// registrations to be added, and we'll need to cancel them before freeing this memory.
// We also need to set request->terminate first, before adding additional service instances,
- // because the uds_validatelists uses the request->terminate function pointer to determine
+ // because the udsserver_validatelists uses the request->terminate function pointer to determine
// what kind of request this is, and therefore what kind of list validation is required.
- request->terminate = regservice_termination_callback;
-
- err = register_service_instance(request, &d);
-
-#if TARGET_OS_EMBEDDED
- ++curr_num_regservices;
- if (curr_num_regservices > max_num_regservices)
- max_num_regservices = curr_num_regservices;
-#endif
+ request->terminate = NULL;
-#if 0
- err = AuthorizedDomain(request, &d, AutoRegistrationDomains) ? register_service_instance(request, &d) : mStatus_NoError;
-#endif
- if (!err)
+#if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
+ if (os_feature_enabled(mDNSResponder, bonjour_privacy) &&
+ (request->u.servicereg.default_domain || IsLocalDomain(&d)))
{
- if (request->u.servicereg.autoname) UpdateDeviceInfoRecord(&mDNSStorage);
-
- if (!*domain)
+ err = _handle_regservice_request_with_trust(request, &d);
+ if (err == mStatus_NoAuth && request->u.servicereg.txtdata)
{
- DNameListElem *ptr;
- // Note that we don't report errors for non-local, non-explicit domains
- for (ptr = AutoRegistrationDomains; ptr; ptr = ptr->next)
- if (!ptr->uid || SystemUID(request->uid) || request->uid == ptr->uid)
- register_service_instance(request, &ptr->name);
+ freeL("service_info txtdata", request->u.servicereg.txtdata);
+ request->u.servicereg.txtdata = NULL;
}
}
+ else
+ {
+ err = _handle_regservice_request_start(request, &d);
+ }
+#else
+ err = _handle_regservice_request_start(request, &d);
+#endif
return(err);
@@ -2095,9 +2500,11 @@ mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const Resourc
validReply:
- LogOperation("%3d: DNSServiceBrowse(%##s, %s) RESULT %s interface %d: %s",
- req->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "ADD" : "RMV",
- mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID, mDNSfalse), RRDisplayString(m, answer));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d->Q%d] DNSServiceBrowse(" PRI_DM_NAME ", " PUB_S ") RESULT " PUB_S " interface %d: " PRI_S,
+ req->request_id, mDNSVal16(question->TargetQID), DM_NAME_PARAM(&question->qname), DNSTypeName(question->qtype),
+ AddRecord ? "ADD" : "RMV", mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID, mDNSfalse),
+ RRDisplayString(m, answer));
append_reply(req, rep);
}
@@ -2139,12 +2546,11 @@ mDNSlocal mStatus add_domain_to_browser(request_state *info, const domainname *d
{ debugf("add_domain_to_browser %##s already in list", d->c); return mStatus_AlreadyRegistered; }
}
- b = mallocL("browser_t", sizeof(*b));
+ b = (browser_t *) callocL("browser_t", sizeof(*b));
if (!b) return mStatus_NoMemoryErr;
- mDNSPlatformMemZero(b, sizeof(*b));
AssignDomainName(&b->domain, d);
SetQuestionPolicy(&b->q, info);
- err = mDNS_StartBrowse(&mDNSStorage, &b->q, &info->u.browser.regtype, d, info->u.browser.AnonData, info->u.browser.interface_id, info->flags,
+ err = mDNS_StartBrowse(&mDNSStorage, &b->q, &info->u.browser.regtype, d, info->u.browser.interface_id, info->flags,
info->u.browser.ForceMCast, (info->flags & kDNSServiceFlagsBackgroundTrafficClass) != 0, FoundInstance, info);
if (err)
{
@@ -2167,13 +2573,15 @@ mDNSlocal mStatus add_domain_to_browser(request_state *info, const domainname *d
#endif // APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
LogMcastQ(&b->q, info, q_start);
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
if (callExternalHelpers(info->u.browser.interface_id, &b->domain, info->flags))
{
domainname tmp;
ConstructServiceName(&tmp, NULL, &info->u.browser.regtype, &b->domain);
LogDebug("add_domain_to_browser: calling external_start_browsing_for_service()");
- external_start_browsing_for_service(info->u.browser.interface_id, &tmp, kDNSType_PTR, info->flags);
+ external_start_browsing_for_service(info->u.browser.interface_id, &tmp, kDNSType_PTR, info->flags, info->process_id);
}
+#endif
}
return err;
}
@@ -2186,22 +2594,23 @@ mDNSlocal void browse_termination_callback(request_state *info)
LogInfo("%3d: DNSServiceBrowse Cancel WAB PID[%d](%s)", info->sd, info->process_id, info->pid_name);
uDNS_StopWABQueries(&mDNSStorage, UDNS_WAB_LBROWSE_QUERY);
}
- if (info->u.browser.AnonData)
- freeL("Anonymous", (void *)info->u.browser.AnonData);
while (info->u.browser.browsers)
{
browser_t *ptr = info->u.browser.browsers;
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
if (callExternalHelpers(ptr->q.InterfaceID, &ptr->domain, ptr->q.flags))
{
domainname tmp;
ConstructServiceName(&tmp, NULL, &info->u.browser.regtype, &ptr->domain);
LogInfo("browse_termination_callback: calling external_stop_browsing_for_service()");
- external_stop_browsing_for_service(ptr->q.InterfaceID, &tmp, kDNSType_PTR, ptr->q.flags);
+ external_stop_browsing_for_service(ptr->q.InterfaceID, &tmp, kDNSType_PTR, ptr->q.flags, info->process_id);
}
-
- LogOperation("%3d: DNSServiceBrowse(%X, %d, \"%##s\") STOP PID[%d](%s)",
- info->sd, info->flags, info->interfaceIndex, ptr->q.qname.c, info->process_id, info->pid_name);
+#endif
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceBrowse(%X, %d, \"" PRI_DM_NAME "\") STOP PID[%d](" PUB_S ")",
+ info->request_id, info->flags, info->interfaceIndex, DM_NAME_PARAM(&ptr->q.qname),
+ info->process_id, info->pid_name);
info->u.browser.browsers = ptr->next;
mDNS_StopBrowse(&mDNSStorage, &ptr->q); // no need to error-check result
@@ -2278,7 +2687,7 @@ mDNSlocal void RegisterLocalOnlyDomainEnumPTR(mDNS *m, const domainname *d, int
{
// allocate/register legacy and non-legacy _browse PTR record
mStatus err;
- ARListElem *ptr = mDNSPlatformMemAllocate(sizeof(*ptr));
+ ARListElem *ptr = (ARListElem *) mDNSPlatformMemAllocateClear(sizeof(*ptr));
debugf("Incrementing %s refcount for %##s",
(type == mDNS_DomainTypeBrowse ) ? "browse domain " :
@@ -2330,7 +2739,7 @@ mDNSlocal void DeregisterLocalOnlyDomainEnumPTR(mDNS *m, const domainname *d, in
mDNSlocal void AddAutoBrowseDomain(const mDNSu32 uid, const domainname *const name)
{
- DNameListElem *new = mDNSPlatformMemAllocate(sizeof(DNameListElem));
+ DNameListElem *new = (DNameListElem *) mDNSPlatformMemAllocateClear(sizeof(*new));
if (!new) { LogMsg("ERROR: malloc"); return; }
AssignDomainName(&new->name, name);
new->uid = uid;
@@ -2508,14 +2917,143 @@ mDNSlocal void AutomaticBrowseDomainChange(mDNS *const m, DNSQuestion *q, const
else RmvAutoBrowseDomain(0, &answer->rdata->u.name);
}
+mDNSlocal mStatus _handle_browse_request_start(request_state *request, const char * domain)
+{
+ domainname d;
+ mStatus err = mStatus_NoError;
+
+ request->terminate = browse_termination_callback;
+
+ if (domain[0])
+ {
+ if (!MakeDomainNameFromDNSNameString(&d, domain)) return(mStatus_BadParamErr);
+ err = add_domain_to_browser(request, &d);
+ }
+ else
+ {
+ DNameListElem *sdom;
+ for (sdom = AutoBrowseDomains; sdom; sdom = sdom->next)
+ if (!sdom->uid || SystemUID(request->uid) || request->uid == sdom->uid)
+ {
+ err = add_domain_to_browser(request, &sdom->name);
+ if (err)
+ {
+ if (SameDomainName(&sdom->name, &localdomain)) break;
+ else err = mStatus_NoError; // suppress errors for non-local "default" domains
+ }
+ }
+ }
+
+ return(err);
+}
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
+
+mDNSlocal void _return_browse_request_error(request_state *request, mStatus error)
+{
+ reply_state *rep;
+
+ GenerateBrowseReply(NULL, 0, request, &rep, browse_reply_op, 0, error);
+
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceBrowse _return_browse_request_error: error (%d)", request->request_id, error);
+
+ append_reply(request, rep);
+}
+
+mDNSlocal mStatus _handle_browse_request_with_trust(request_state *request, const char * domain)
+{
+ mStatus err;
+ if (audit_token_to_pid(request->audit_token) == 0)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_WARNING, "[R%u] _handle_browse_request_with_trust: no audit token for pid(%s %d)", request->request_id, request->pid_name, request->process_id);
+ err = _handle_browse_request_start(request, domain);
+ }
+ else
+ {
+ char typestr[MAX_ESCAPED_DOMAIN_NAME];
+ typestr[0] = 0;
+ (void)ConvertDomainNameToCString(&request->u.browser.regtype, typestr);
+ mdns_trust_flags_t flags = mdns_trust_flags_none;
+ mdns_trust_status_t status = mdns_trust_check_bonjour(request->audit_token, typestr, &flags);
+ switch (status)
+ {
+ case mdns_trust_status_denied:
+ case mdns_trust_status_pending:
+ {
+ mdns_trust_t trust = mdns_trust_create(request->audit_token, typestr, flags);
+ if (!trust )
+ {
+ err = mStatus_NoMemoryErr;
+ goto exit;
+ }
+
+ size_t len = strlen(domain) + 1;
+ void * context = mallocL("context/_handle_browse_request_with_trust", len);
+ if (!context)
+ {
+ my_perror("ERROR: mallocL context/_handle_browse_request_with_trust");
+ mdns_release(trust);
+ err = mStatus_NoMemoryErr;
+ goto exit;
+ }
+ memcpy(context, domain, len);
+ mdns_trust_set_context(trust, context);
+
+ mdns_trust_set_queue(trust, _get_trust_results_dispatch_queue());
+ mdns_trust_set_event_handler(trust, ^(mdns_trust_event_t event, mdns_trust_status_t update)
+ {
+ if (event == mdns_trust_event_result)
+ {
+ mStatus error = (update != mdns_trust_status_granted) ? mStatus_PolicyDenied : mStatus_NoError;
+ KQueueLock();
+ const char * _domain = mdns_trust_get_context(trust);
+ if (_domain)
+ {
+ if (!error)
+ {
+ error = _handle_browse_request_start(request, _domain);
+ // No context means the request was canceled before we got here
+ }
+ if (error) // (not else if) Always check for error result
+ {
+ _return_browse_request_error(request, error);
+ }
+ }
+ KQueueUnlock("_handle_browse_request_with_trust");
+ }
+ });
+ request->trust = trust;
+ mdns_trust_activate(trust);
+ err = mStatus_NoError;
+ break;
+ }
+
+ case mdns_trust_status_no_entitlement:
+ err = mStatus_NoAuth;
+ break;
+
+ case mdns_trust_status_granted:
+ err = _handle_browse_request_start(request, domain);
+ break;
+
+ default:
+ err = mStatus_UnknownErr;
+ break;
+ }
+ }
+exit:
+ return err;
+}
+#endif // TRUST_ENFORCEMENT
+
mDNSlocal mStatus handle_browse_request(request_state *request)
{
+ // Note that regtype may include a trailing subtype
char regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
- domainname typedn, d, temp;
+ domainname typedn, temp;
mDNSs32 NumSubTypes;
- char *AnonData = mDNSNULL;
mStatus err = mStatus_NoError;
- int AnonDataLen;
DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
@@ -2538,32 +3076,20 @@ mDNSlocal mStatus handle_browse_request(request_state *request)
LogInfo("handle_browse_request: browse pending for interface index %d", interfaceIndex);
}
- if (get_string(&request->msgptr, request->msgend, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
- get_string(&request->msgptr, request->msgend, domain, MAX_ESCAPED_DOMAIN_NAME) < 0) return(mStatus_BadParamErr);
+ if (get_string(&request->msgptr, request->msgend, regtype, sizeof(regtype)) < 0 ||
+ get_string(&request->msgptr, request->msgend, domain, sizeof(domain )) < 0) return(mStatus_BadParamErr);
if (!request->msgptr) { LogMsg("%3d: DNSServiceBrowse(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
request->flags = flags;
request->interfaceIndex = interfaceIndex;
typedn.c[0] = 0;
- NumSubTypes = ChopSubTypes(regtype, &AnonData); // Note: Modifies regtype string to remove trailing subtypes
+ NumSubTypes = ChopSubTypes(regtype); // Note: Modifies regtype string to remove trailing subtypes
if (NumSubTypes < 0 || NumSubTypes > 1)
return(mStatus_BadParamErr);
- AnonDataLen = 0;
- if (AnonData)
- {
- AnonDataLen = strlen(AnonData);
- if (AnonDataLen > MAX_ANONYMOUS_DATA)
- {
- LogMsg("handle_browse_request: AnonDataLen %d", AnonDataLen);
- return(mStatus_BadParamErr);
- }
- // Account for the null byte
- AnonDataLen += 1;
- }
if (NumSubTypes == 1)
{
- if (!AppendDNSNameString(&typedn, regtype + strlen(regtype) + 1 + AnonDataLen))
+ if (!AppendDNSNameString(&typedn, regtype + strlen(regtype) + 1))
return(mStatus_BadParamErr);
}
@@ -2580,49 +3106,39 @@ mDNSlocal mStatus handle_browse_request(request_state *request)
request->u.browser.default_domain = !domain[0];
request->u.browser.browsers = NULL;
- LogOperation("%3d: DNSServiceBrowse(%X, %d, \"%##s\", \"%s\") START PID[%d](%s)",
- request->sd, request->flags, interfaceIndex, request->u.browser.regtype.c, domain, request->process_id, request->pid_name);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%d] DNSServiceBrowse(%X, %d, \"" PRI_DM_NAME "\", \"" PRI_S "\") START PID[%d](" PUB_S ")",
+ request->request_id, request->flags, interfaceIndex, DM_NAME_PARAM(&request->u.browser.regtype), domain,
+ request->process_id, request->pid_name);
if (request->u.browser.default_domain)
{
// Start the domain enumeration queries to discover the WAB browse domains
- LogInfo("%3d: DNSServiceBrowse Start WAB PID[%d](%s)", request->sd, request->process_id, request->pid_name);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceBrowse Start WAB PID[%d](" PUB_S ")",
+ request->request_id, request->process_id, request->pid_name);
uDNS_StartWABQueries(&mDNSStorage, UDNS_WAB_LBROWSE_QUERY);
}
- request->u.browser.AnonData = mDNSNULL;
- if (AnonData)
- {
- int len = strlen(AnonData) + 1;
- request->u.browser.AnonData = mallocL("Anonymous", len);
- if (!request->u.browser.AnonData)
- return mStatus_NoMemoryErr;
- else
- mDNSPlatformMemCopy((void *)request->u.browser.AnonData, AnonData, len);
- }
// We need to unconditionally set request->terminate, because even if we didn't successfully
// start any browses right now, subsequent configuration changes may cause successful
// browses to be added, and we'll need to cancel them before freeing this memory.
- request->terminate = browse_termination_callback;
+ request->terminate = NULL;
- if (domain[0])
+#if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
+ domainname d;
+ if (!MakeDomainNameFromDNSNameString(&d, domain)) return(mStatus_BadParamErr);
+
+ if (os_feature_enabled(mDNSResponder, bonjour_privacy) &&
+ (request->u.browser.default_domain || IsLocalDomain(&d) || request->u.browser.ForceMCast))
{
- if (!MakeDomainNameFromDNSNameString(&d, domain)) return(mStatus_BadParamErr);
- err = add_domain_to_browser(request, &d);
+ err = _handle_browse_request_with_trust(request, domain);
}
else
{
- DNameListElem *sdom;
- for (sdom = AutoBrowseDomains; sdom; sdom = sdom->next)
- if (!sdom->uid || SystemUID(request->uid) || request->uid == sdom->uid)
- {
- err = add_domain_to_browser(request, &sdom->name);
- if (err)
- {
- if (SameDomainName(&sdom->name, &localdomain)) break;
- else err = mStatus_NoError; // suppress errors for non-local "default" domains
- }
- }
+ err = _handle_browse_request_start(request, domain);
}
+#else
+ err = _handle_browse_request_start(request, domain);
+#endif
return(err);
}
@@ -2633,6 +3149,61 @@ mDNSlocal mStatus handle_browse_request(request_state *request)
#pragma mark - DNSServiceResolve
#endif
+mDNSlocal void resolve_termination_callback(request_state *request)
+{
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceResolve(%X, %d, \"" PRI_DM_NAME "\") STOP PID[%d](" PUB_S ")",
+ request->request_id, request->flags, request->interfaceIndex, DM_NAME_PARAM(&request->u.resolve.qtxt.qname),
+ request->process_id, request->pid_name);
+ mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qtxt);
+ mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qsrv);
+ LogMcastQ(&request->u.resolve.qsrv, request, q_stop);
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+ if (request->u.resolve.external_advertise)
+ {
+ external_stop_resolving_service(request->u.resolve.qsrv.InterfaceID, &request->u.resolve.qsrv.qname, request->flags, request->process_id);
+ }
+#endif
+}
+
+typedef struct {
+ char regtype[MAX_ESCAPED_DOMAIN_NAME];
+ domainname fqdn;
+ mDNSInterfaceID InterfaceID;
+} _resolve_start_params_t;
+
+mDNSlocal mStatus _handle_resolve_request_start(request_state *request, const _resolve_start_params_t * const params)
+{
+ mStatus err;
+
+ err = mDNS_StartQuery(&mDNSStorage, &request->u.resolve.qsrv);
+
+ if (!err)
+ {
+ err = mDNS_StartQuery(&mDNSStorage, &request->u.resolve.qtxt);
+ if (err)
+ {
+ mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qsrv);
+ }
+ else
+ {
+ request->terminate = resolve_termination_callback;
+ LogMcastQ(&request->u.resolve.qsrv, request, q_start);
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+ if (callExternalHelpers(params->InterfaceID, &params->fqdn, request->flags))
+ {
+ request->u.resolve.external_advertise = mDNStrue;
+ LogInfo("handle_resolve_request: calling external_start_resolving_service()");
+ external_start_resolving_service(params->InterfaceID, &params->fqdn, request->flags, request->process_id);
+ }
+#else
+ (void)params;
+#endif
+ }
+ }
+ return err;
+}
+
mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
{
size_t len = 0;
@@ -2690,31 +3261,139 @@ mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, con
put_uint16(req->u.resolve.txt->rdlength, &data);
put_rdata (req->u.resolve.txt->rdlength, req->u.resolve.txt->rdata->u.data, &data);
- LogOperation("%3d: DNSServiceResolve(%s) RESULT %s:%d", req->sd, fullname, target, mDNSVal16(req->u.resolve.srv->rdata->u.srv.port));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%d->Q%d] DNSServiceResolve(" PRI_S ") RESULT " PRI_S ":%d",
+ req->request_id, mDNSVal16(question->TargetQID), fullname, target,
+ mDNSVal16(req->u.resolve.srv->rdata->u.srv.port));
append_reply(req, rep);
}
-mDNSlocal void resolve_termination_callback(request_state *request)
+#if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
+
+mDNSlocal void _return_resolve_request_error(request_state * request, mStatus error)
{
- LogOperation("%3d: DNSServiceResolve(%X, %d, \"%##s\") STOP PID[%d](%s)",
- request->sd, request->flags, request->interfaceIndex, request->u.resolve.qtxt.qname.c, request->process_id, request->pid_name);
- mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qtxt);
- mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qsrv);
- LogMcastQ(&request->u.resolve.qsrv, request, q_stop);
- if (request->u.resolve.external_advertise)
- external_stop_resolving_service(request->u.resolve.qsrv.InterfaceID, &request->u.resolve.qsrv.qname, request->flags);
+ size_t len;
+ char * emptystr = "\0";
+ char * data;
+ reply_state *rep;
+
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u] DNSServiceResolve _return_resolve_request_error: error(%d)", request->request_id, error);
+
+ // calculate reply length
+ len = sizeof(DNSServiceFlags);
+ len += sizeof(mDNSu32); // interface index
+ len += sizeof(DNSServiceErrorType);
+ len += 2; // name, target
+ len += 2 * sizeof(mDNSu16); // port, txtLen
+ len += 0; //req->u.resolve.txt->rdlength;
+
+ rep = create_reply(resolve_reply_op, len, request);
+
+ rep->rhdr->flags = 0;
+ rep->rhdr->ifi = 0;
+ rep->rhdr->error = dnssd_htonl(error);
+
+ data = (char *)&rep->rhdr[1];
+
+ // write reply data to message
+ put_string(emptystr, &data); // name
+ put_string(emptystr, &data); // target
+ put_uint16(0, &data); // port
+ put_uint16(0, &data); // txtLen
+
+ append_reply(request, rep);
+}
+
+mDNSlocal mStatus _handle_resolve_request_with_trust(request_state *request, const _resolve_start_params_t * const params)
+{
+ mStatus err;
+ if (audit_token_to_pid(request->audit_token) == 0)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_WARNING, "[R%u] _handle_resolve_request_with_trust: no audit token for pid(%s %d)", request->request_id, request->pid_name, request->process_id);
+ err = _handle_resolve_request_start(request, params);
+ }
+ else
+ {
+ mdns_trust_flags_t flags = mdns_trust_flags_none;
+ mdns_trust_status_t status = mdns_trust_check_bonjour(request->audit_token, params->regtype, &flags);
+ switch (status)
+ {
+ case mdns_trust_status_denied:
+ case mdns_trust_status_pending:
+ {
+ mdns_trust_t trust = mdns_trust_create(request->audit_token, params->regtype, flags);
+ if (!trust )
+ {
+ err = mStatus_NoMemoryErr;
+ goto exit;
+ }
+
+ void * context = mallocL("context/_handle_resolve_request_with_trust", sizeof(_resolve_start_params_t));
+ if (!context)
+ {
+ my_perror("ERROR: mallocL context/_handle_resolve_request_with_trust");
+ mdns_release(trust);
+ err = mStatus_NoMemoryErr;
+ goto exit;
+ }
+ memcpy(context, params, sizeof(_resolve_start_params_t));
+ mdns_trust_set_context(trust, context);
+ mdns_trust_set_queue(trust, _get_trust_results_dispatch_queue());
+ mdns_trust_set_event_handler(trust, ^(mdns_trust_event_t event, mdns_trust_status_t update)
+ {
+ if (event == mdns_trust_event_result)
+ {
+ mStatus error = (update != mdns_trust_status_granted) ? mStatus_PolicyDenied : mStatus_NoError;
+ KQueueLock();
+ _resolve_start_params_t * _params = mdns_trust_get_context(trust);
+ if (_params)
+ {
+ if (!error)
+ {
+ error = _handle_resolve_request_start(request, _params);
+ // No context means the request was canceled before we got here
+ }
+ if (error) // (not else if) Always check for error result
+ {
+ _return_resolve_request_error(request, error);
+ }
+ }
+ KQueueUnlock("_handle_resolve_request_with_trust");
+ }
+ });
+ request->trust = trust;
+ mdns_trust_activate(trust);
+ err = mStatus_NoError;
+ break;
+ }
+
+ case mdns_trust_status_no_entitlement:
+ err = mStatus_NoAuth;
+ break;
+
+ case mdns_trust_status_granted:
+ err = _handle_resolve_request_start(request, params);
+ break;
+
+ default:
+ err = mStatus_UnknownErr;
+ break;
+ }
+ }
+exit:
+ return err;
}
+#endif // TRUST_ENFORCEMENT
mDNSlocal mStatus handle_resolve_request(request_state *request)
{
- char name[256], regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
- domainname fqdn;
+ char name[256], domain[MAX_ESCAPED_DOMAIN_NAME];
+ _resolve_start_params_t params;
mStatus err;
// extract the data from the message
DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
- mDNSInterfaceID InterfaceID;
// Map kDNSServiceInterfaceIndexP2P to kDNSServiceInterfaceIndexAny with the kDNSServiceFlagsIncludeP2P
// flag set so that the resolve will run over P2P interfaces that are not yet created.
@@ -2725,11 +3404,11 @@ mDNSlocal mStatus handle_resolve_request(request_state *request)
interfaceIndex = kDNSServiceInterfaceIndexAny;
}
- InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
+ params.InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
// The operation is scoped to a specific interface index, but the
// interface is not currently in our list.
- if (interfaceIndex && !InterfaceID)
+ if (interfaceIndex && !params.InterfaceID)
{
// If it's one of the specially defined inteface index values, just return an error.
if (PreDefinedInterfaceIndex(interfaceIndex))
@@ -2740,19 +3419,19 @@ mDNSlocal mStatus handle_resolve_request(request_state *request)
// Otherwise, use the specified interface index value and the operation will
// be applied to that interface when it comes up.
- InterfaceID = (mDNSInterfaceID)(uintptr_t)interfaceIndex;
+ params.InterfaceID = (mDNSInterfaceID)(uintptr_t)interfaceIndex;
LogInfo("handle_resolve_request: resolve pending for interface index %d", interfaceIndex);
}
- if (get_string(&request->msgptr, request->msgend, name, 256) < 0 ||
- get_string(&request->msgptr, request->msgend, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
- get_string(&request->msgptr, request->msgend, domain, MAX_ESCAPED_DOMAIN_NAME) < 0)
+ if (get_string(&request->msgptr, request->msgend, name, sizeof(name )) < 0 ||
+ get_string(&request->msgptr, request->msgend, params.regtype, sizeof(params.regtype)) < 0 ||
+ get_string(&request->msgptr, request->msgend, domain, sizeof(domain )) < 0)
{ LogMsg("ERROR: handle_resolve_request - Couldn't read name/regtype/domain"); return(mStatus_BadParamErr); }
if (!request->msgptr) { LogMsg("%3d: DNSServiceResolve(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
- if (build_domainname_from_strings(&fqdn, name, regtype, domain) < 0)
- { LogMsg("ERROR: handle_resolve_request bad “%s” “%s” “%s”", name, regtype, domain); return(mStatus_BadParamErr); }
+ if (build_domainname_from_strings(&params.fqdn, name, params.regtype, domain) < 0)
+ { LogMsg("ERROR: handle_resolve_request bad “%s” “%s” “%s”", name, params.regtype, domain); return(mStatus_BadParamErr); }
mDNSPlatformMemZero(&request->u.resolve, sizeof(request->u.resolve));
@@ -2769,10 +3448,9 @@ mDNSlocal mStatus handle_resolve_request(request_state *request)
request->interfaceIndex = interfaceIndex;
// format questions
- request->u.resolve.qsrv.InterfaceID = InterfaceID;
+ request->u.resolve.qsrv.InterfaceID = params.InterfaceID;
request->u.resolve.qsrv.flags = flags;
- request->u.resolve.qsrv.Target = zeroAddr;
- AssignDomainName(&request->u.resolve.qsrv.qname, &fqdn);
+ AssignDomainName(&request->u.resolve.qsrv.qname, &params.fqdn);
request->u.resolve.qsrv.qtype = kDNSType_SRV;
request->u.resolve.qsrv.qclass = kDNSClass_IN;
request->u.resolve.qsrv.LongLived = (flags & kDNSServiceFlagsLongLivedQuery ) != 0;
@@ -2780,26 +3458,19 @@ mDNSlocal mStatus handle_resolve_request(request_state *request)
request->u.resolve.qsrv.ForceMCast = (flags & kDNSServiceFlagsForceMulticast ) != 0;
request->u.resolve.qsrv.ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
request->u.resolve.qsrv.SuppressUnusable = mDNSfalse;
- request->u.resolve.qsrv.SearchListIndex = 0;
request->u.resolve.qsrv.AppendSearchDomains = 0;
- request->u.resolve.qsrv.RetryWithSearchDomains = mDNSfalse;
request->u.resolve.qsrv.TimeoutQuestion = 0;
request->u.resolve.qsrv.WakeOnResolve = (flags & kDNSServiceFlagsWakeOnResolve) != 0;
- request->u.resolve.qsrv.UseBackgroundTrafficClass = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
- request->u.resolve.qsrv.ValidationRequired = 0;
- request->u.resolve.qsrv.ValidatingResponse = 0;
+ request->u.resolve.qsrv.UseBackgroundTraffic = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
request->u.resolve.qsrv.ProxyQuestion = 0;
- request->u.resolve.qsrv.qnameOrig = mDNSNULL;
- request->u.resolve.qsrv.AnonInfo = mDNSNULL;
request->u.resolve.qsrv.pid = request->process_id;
request->u.resolve.qsrv.euid = request->uid;
request->u.resolve.qsrv.QuestionCallback = resolve_result_callback;
request->u.resolve.qsrv.QuestionContext = request;
- request->u.resolve.qtxt.InterfaceID = InterfaceID;
+ request->u.resolve.qtxt.InterfaceID = params.InterfaceID;
request->u.resolve.qtxt.flags = flags;
- request->u.resolve.qtxt.Target = zeroAddr;
- AssignDomainName(&request->u.resolve.qtxt.qname, &fqdn);
+ AssignDomainName(&request->u.resolve.qtxt.qname, &params.fqdn);
request->u.resolve.qtxt.qtype = kDNSType_TXT;
request->u.resolve.qtxt.qclass = kDNSClass_IN;
request->u.resolve.qtxt.LongLived = (flags & kDNSServiceFlagsLongLivedQuery ) != 0;
@@ -2807,17 +3478,11 @@ mDNSlocal mStatus handle_resolve_request(request_state *request)
request->u.resolve.qtxt.ForceMCast = (flags & kDNSServiceFlagsForceMulticast ) != 0;
request->u.resolve.qtxt.ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
request->u.resolve.qtxt.SuppressUnusable = mDNSfalse;
- request->u.resolve.qtxt.SearchListIndex = 0;
request->u.resolve.qtxt.AppendSearchDomains = 0;
- request->u.resolve.qtxt.RetryWithSearchDomains = mDNSfalse;
request->u.resolve.qtxt.TimeoutQuestion = 0;
request->u.resolve.qtxt.WakeOnResolve = 0;
- request->u.resolve.qtxt.UseBackgroundTrafficClass = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
- request->u.resolve.qtxt.ValidationRequired = 0;
- request->u.resolve.qtxt.ValidatingResponse = 0;
+ request->u.resolve.qtxt.UseBackgroundTraffic = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
request->u.resolve.qtxt.ProxyQuestion = 0;
- request->u.resolve.qtxt.qnameOrig = mDNSNULL;
- request->u.resolve.qtxt.AnonInfo = mDNSNULL;
request->u.resolve.qtxt.pid = request->process_id;
request->u.resolve.qtxt.euid = request->uid;
request->u.resolve.qtxt.QuestionCallback = resolve_result_callback;
@@ -2832,30 +3497,28 @@ mDNSlocal mStatus handle_resolve_request(request_state *request)
#endif
// ask the questions
- LogOperation("%3d: DNSServiceResolve(%X, %d, \"%##s\") START PID[%d](%s)", request->sd, flags, interfaceIndex,
- request->u.resolve.qsrv.qname.c, request->process_id, request->pid_name);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceResolve(%X, %d, \"" PRI_DM_NAME "\") START PID[%d](" PUB_S ")",
+ request->request_id, flags, interfaceIndex, DM_NAME_PARAM(&request->u.resolve.qsrv.qname),
+ request->process_id, request->pid_name);
- err = mDNS_StartQuery(&mDNSStorage, &request->u.resolve.qsrv);
+ request->terminate = NULL;
+#if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
+ domainname d;
+ if (!MakeDomainNameFromDNSNameString(&d, domain)) return(mStatus_BadParamErr);
- if (!err)
+ if (os_feature_enabled(mDNSResponder, bonjour_privacy) &&
+ (IsLocalDomain(&d) || request->u.resolve.qsrv.ForceMCast))
{
- err = mDNS_StartQuery(&mDNSStorage, &request->u.resolve.qtxt);
- if (err)
- {
- mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qsrv);
- }
- else
- {
- request->terminate = resolve_termination_callback;
- LogMcastQ(&request->u.resolve.qsrv, request, q_start);
- if (callExternalHelpers(InterfaceID, &fqdn, flags))
- {
- request->u.resolve.external_advertise = mDNStrue;
- LogInfo("handle_resolve_request: calling external_start_resolving_service()");
- external_start_resolving_service(InterfaceID, &fqdn, flags);
- }
- }
+ err = _handle_resolve_request_with_trust(request, &params);
+ }
+ else
+ {
+ err = _handle_resolve_request_start(request, &params);
}
+#else
+ err = _handle_resolve_request_start(request, &params);
+#endif
return(err);
}
@@ -2866,328 +3529,55 @@ mDNSlocal mStatus handle_resolve_request(request_state *request)
#pragma mark - DNSServiceQueryRecord
#endif
-// mDNS operation functions. Each operation has 3 associated functions - a request handler that parses
-// the client's request and makes the appropriate mDNSCore call, a result handler (passed as a callback
-// to the mDNSCore routine) that sends results back to the client, and a termination routine that aborts
-// the mDNSCore operation if the client dies or closes its socket.
-
-// Returns -1 to tell the caller that it should not try to reissue the query anymore
-// Returns 1 on successfully appending a search domain and the caller should reissue the new query
-// Returns 0 when there are no more search domains and the caller should reissue the query
-mDNSlocal int AppendNewSearchDomain(DNSQuestion *question)
+mDNSlocal void queryrecord_result_reply(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord, DNSServiceErrorType error, void *context)
{
- domainname *sd;
- mStatus err;
-
- // Sanity check: The caller already checks this. We use -1 to indicate that we have searched all
- // the domains and should try the single label query directly on the wire.
- if (question->SearchListIndex == -1)
- {
- LogMsg("AppendNewSearchDomain: question %##s (%s) SearchListIndex is -1", question->qname.c, DNSTypeName(question->qtype));
- return -1;
- }
-
- if (!question->AppendSearchDomains)
- {
- LogMsg("AppendNewSearchDomain: question %##s (%s) AppendSearchDoamins is 0", question->qname.c, DNSTypeName(question->qtype));
- return -1;
- }
-
- // Save the original name, before we modify them below.
- if (!question->qnameOrig)
- {
- question->qnameOrig = mallocL("AppendNewSearchDomain", sizeof(domainname));
- if (!question->qnameOrig) { LogMsg("AppendNewSearchDomain: ERROR!! malloc failure"); return -1; }
- question->qnameOrig->c[0] = 0;
- AssignDomainName(question->qnameOrig, &question->qname);
- LogInfo("AppendSearchDomain: qnameOrig %##s", question->qnameOrig->c);
- }
-
- sd = uDNS_GetNextSearchDomain(question->InterfaceID, &question->SearchListIndex, !question->AppendLocalSearchDomains);
- // We use -1 to indicate that we have searched all the domains and should try the single label
- // query directly on the wire. uDNS_GetNextSearchDomain should never return a negative value
- if (question->SearchListIndex == -1)
- {
- LogMsg("AppendNewSearchDomain: ERROR!! uDNS_GetNextSearchDomain returned -1");
- return -1;
- }
-
- // Not a common case. Perhaps, we should try the next search domain if it exceeds ?
- if (sd && (DomainNameLength(question->qnameOrig) + DomainNameLength(sd)) > MAX_DOMAIN_NAME)
- {
- LogMsg("AppendNewSearchDomain: ERROR!! exceeding max domain length for %##s (%s) SearchDomain %##s length %d, Question name length %d", question->qnameOrig->c, DNSTypeName(question->qtype), sd->c, DomainNameLength(question->qnameOrig), DomainNameLength(sd));
- return -1;
- }
-
- // if there are no more search domains and we have already tried this question
- // without appending search domains, then we are done.
- if (!sd && !ApplySearchDomainsFirst(question))
- {
- LogInfo("AppendNewSearchDomain: No more search domains for question with name %##s (%s), not trying anymore", question->qname.c, DNSTypeName(question->qtype));
- return -1;
- }
-
- // Stop the question before changing the name as negative cache entries could be pointing at this question.
- // Even if we don't change the question in the case of returning 0, the caller is going to restart the
- // question.
- err = mDNS_StopQuery(&mDNSStorage, question);
- if (err) { LogMsg("AppendNewSearchDomain: ERROR!! %##s %s mDNS_StopQuery: %d, while retrying with search domains", question->qname.c, DNSTypeName(question->qtype), (int)err); }
-
- AssignDomainName(&question->qname, question->qnameOrig);
- if (sd)
- {
- AppendDomainName(&question->qname, sd);
- LogInfo("AppnedNewSearchDomain: Returning question with name %##s, SearchListIndex %d", question->qname.c, question->SearchListIndex);
- return 1;
- }
-
- // Try the question as single label
- LogInfo("AppnedNewSearchDomain: No more search domains for question with name %##s (%s), trying one last time", question->qname.c, DNSTypeName(question->qtype));
- return 0;
-}
-
-#if APPLE_OSX_mDNSResponder
+ char name[MAX_ESCAPED_DOMAIN_NAME];
+ size_t len;
+ DNSServiceFlags flags = 0;
+ reply_state *rep;
+ char *data;
+ request_state *req = (request_state *)context;
+ const char *dnssec_result_description = "";
-mDNSlocal mDNSBool DomainInSearchList(const domainname *domain, mDNSBool excludeLocal)
-{
- const SearchListElem *s;
- int qcount, scount;
+ ConvertDomainNameToCString(answer->name, name);
- qcount = CountLabels(domain);
- for (s=SearchList; s; s=s->next)
- {
- if (excludeLocal && SameDomainName(&s->domain, &localdomain))
- continue;
- scount = CountLabels(&s->domain);
- if (qcount >= scount)
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
+ if (question->DNSSECStatus.enable_dnssec) {
+ if (answer->dnssec_result == dnssec_secure)
{
- // Note: When qcount == scount, we do a complete match of the domain
- // which is expected by the callers.
- const domainname *d = SkipLeadingLabels(domain, (qcount - scount));
- if (SameDomainName(&s->domain, d))
- {
- return mDNStrue;
- }
+ flags |= kDNSServiceFlagsSecure;
+ dnssec_result_description = ", DNSSEC_Secure";
}
- }
- return mDNSfalse;
-}
-
-// The caller already checks that this is a dotlocal question.
-mDNSlocal mDNSBool ShouldDeliverNegativeResponse(DNSQuestion *question)
-{
- mDNSu16 qtype;
-
- // If the question matches the search domain exactly or the search domain is a
- // subdomain of the question, it is most likely a valid unicast domain and hence
- // don't suppress negative responses.
- //
- // If the user has configured ".local" as a search domain, we don't want
- // to deliver a negative response for names ending in ".local" as that would
- // prevent bonjour discovery. Passing mDNStrue for the last argument excludes
- // ".local" search domains.
- if (DomainInSearchList(&question->qname, mDNStrue))
- {
- LogOperation("ShouldDeliverNegativeResponse: Question %##s (%s) in SearchList", question->qname.c, DNSTypeName(question->qtype));
- return mDNStrue;
- }
-
- // Deliver negative response for A/AAAA if there was a positive response for AAAA/A respectively.
- if (question->qtype != kDNSType_A && question->qtype != kDNSType_AAAA)
- {
- LogOperation("ShouldDeliverNegativeResponse: Question %##s (%s) not answering local question with negative unicast response",
- question->qname.c, DNSTypeName(question->qtype));
- return mDNSfalse;
- }
- qtype = (question->qtype == kDNSType_A ? kDNSType_AAAA : kDNSType_A);
- if (!mDNS_CheckForCacheRecord(&mDNSStorage, question, qtype))
- {
- LogOperation("ShouldDeliverNegativeResponse:Question %##s (%s) not answering local question with negative unicast response"
- " (can't find positive record)", question->qname.c, DNSTypeName(question->qtype));
- return mDNSfalse;
- }
- LogOperation("ShouldDeliverNegativeResponse:Question %##s (%s) answering local with negative unicast response (found positive record)",
- question->qname.c, DNSTypeName(question->qtype));
- return mDNStrue;
-}
-
-// Workaround for networks using Microsoft Active Directory using "local" as a private internal
-// top-level domain
-mDNSlocal mStatus SendAdditionalQuery(DNSQuestion *q, request_state *request, mStatus err)
-{
-#ifndef UNICAST_DISABLED
- extern domainname ActiveDirectoryPrimaryDomain;
- DNSQuestion **question2;
- #define VALID_MSAD_SRV_TRANSPORT(T) (SameDomainLabel((T)->c, (const mDNSu8 *)"\x4_tcp") || SameDomainLabel((T)->c, (const mDNSu8 *)"\x4_udp"))
- #define VALID_MSAD_SRV(Q) ((Q)->qtype == kDNSType_SRV && VALID_MSAD_SRV_TRANSPORT(SecondLabel(&(Q)->qname)))
-
- question2 = mDNSNULL;
- if (request->hdr.op == query_request)
- question2 = &request->u.queryrecord.q2;
- else if (request->hdr.op == addrinfo_request)
- {
- if (q->qtype == kDNSType_A)
- question2 = &request->u.addrinfo.q42;
- else if (q->qtype == kDNSType_AAAA)
- question2 = &request->u.addrinfo.q62;
- }
- if (!question2)
- {
- LogMsg("SendAdditionalQuery: question2 NULL for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- return mStatus_BadParamErr;
- }
-
- // Sanity check: If we already sent an additonal query, we don't need to send one more.
- //
- // 1. When the application calls DNSServiceQueryRecord or DNSServiceGetAddrInfo with a .local name, this function
- // is called to see whether a unicast query should be sent or not.
- //
- // 2. As a result of appending search domains, the question may be end up with a .local suffix even though it
- // was not a .local name to start with. In that case, queryrecord_result_callback calls this function to
- // send the additional query.
- //
- // Thus, it should not be called more than once.
- if (*question2)
- {
- LogInfo("SendAdditionalQuery: question2 already sent for %##s (%s), no more q2", q->qname.c, DNSTypeName(q->qtype));
- return err;
- }
-
- if (!q->ForceMCast && SameDomainLabel(LastLabel(&q->qname), (const mDNSu8 *)&localdomain))
- if (q->qtype == kDNSType_A || q->qtype == kDNSType_AAAA || VALID_MSAD_SRV(q))
+ else if (answer->dnssec_result == dnssec_insecure)
{
- DNSQuestion *q2;
- int labels = CountLabels(&q->qname);
- q2 = mallocL("DNSQuestion", sizeof(DNSQuestion));
- if (!q2) FatalError("ERROR: SendAdditionalQuery malloc");
- *question2 = q2;
- *q2 = *q;
- q2->InterfaceID = mDNSInterface_Unicast;
- q2->ExpectUnique = mDNStrue;
- // Always set the QuestionContext to indicate that this question should be stopped
- // before freeing. Don't rely on "q".
- q2->QuestionContext = request;
- // If the query starts as a single label e.g., somehost, and we have search domains with .local,
- // queryrecord_result_callback calls this function when .local is appended to "somehost".
- // At that time, the name in "q" is pointing at somehost.local and its qnameOrig pointing at
- // "somehost". We need to copy that information so that when we retry with a different search
- // domain e.g., mycompany.local, we get "somehost.mycompany.local".
- if (q->qnameOrig)
- {
- (*question2)->qnameOrig = mallocL("SendAdditionalQuery", DomainNameLength(q->qnameOrig));
- if (!(*question2)->qnameOrig) { LogMsg("SendAdditionalQuery: ERROR!! malloc failure"); return mStatus_NoMemoryErr; }
- (*question2)->qnameOrig->c[0] = 0;
- AssignDomainName((*question2)->qnameOrig, q->qnameOrig);
- LogInfo("SendAdditionalQuery: qnameOrig %##s", (*question2)->qnameOrig->c);
- }
- // For names of the form "<one-or-more-labels>.bar.local." we always do a second unicast query in parallel.
- // For names of the form "<one-label>.local." it's less clear whether we should do a unicast query.
- // If the name being queried is exactly the same as the name in the DHCP "domain" option (e.g. the DHCP
- // "domain" is my-small-company.local, and the user types "my-small-company.local" into their web browser)
- // then that's a hint that it's worth doing a unicast query. Otherwise, we first check to see if the
- // site's DNS server claims there's an SOA record for "local", and if so, that's also a hint that queries
- // for names in the "local" domain will be safely answered privately before they hit the root name servers.
- // Note that in the "my-small-company.local" example above there will typically be an SOA record for
- // "my-small-company.local" but *not* for "local", which is why the "local SOA" check would fail in that case.
- // We need to check against both ActiveDirectoryPrimaryDomain and SearchList. If it matches against either
- // of those, we don't want do the SOA check for the local
- if (labels == 2 && !SameDomainName(&q->qname, &ActiveDirectoryPrimaryDomain) && !DomainInSearchList(&q->qname, mDNSfalse))
- {
- AssignDomainName(&q2->qname, &localdomain);
- q2->qtype = kDNSType_SOA;
- q2->LongLived = mDNSfalse;
- q2->ForceMCast = mDNSfalse;
- q2->ReturnIntermed = mDNStrue;
- // Don't append search domains for the .local SOA query
- q2->AppendSearchDomains = 0;
- q2->AppendLocalSearchDomains = 0;
- q2->RetryWithSearchDomains = mDNSfalse;
- q2->SearchListIndex = 0;
- q2->TimeoutQuestion = 0;
- q2->AnonInfo = mDNSNULL;
- q2->pid = request->process_id;
- q2->euid = request->uid;
- }
- LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) unicast", request->sd, q2->qname.c, DNSTypeName(q2->qtype));
- err = mDNS_StartQuery(&mDNSStorage, q2);
- if (err) LogMsg("%3d: ERROR: DNSServiceQueryRecord %##s %s mDNS_StartQuery: %d", request->sd, q2->qname.c, DNSTypeName(q2->qtype), (int)err);
+ flags |= kDNSServiceFlagsInsecure;
+ dnssec_result_description = ", DNSSEC_Insecure";
}
- return(err);
-#else // !UNICAST_DISABLED
- (void) q;
- (void) request;
- (void) err;
-
- return mStatus_NoError;
-#endif // !UNICAST_DISABLED
-}
-#endif // APPLE_OSX_mDNSResponder
-
-// This function tries to append a search domain if valid and possible. If so, returns true.
-mDNSlocal mDNSBool RetryQuestionWithSearchDomains(DNSQuestion *question, request_state *req, QC_result AddRecord)
-{
- int result;
- // RetryWithSearchDomains tells the core to call us back so that we can retry with search domains if there is no
- // answer in the cache or /etc/hosts. In the first call back from the core, we clear RetryWithSearchDomains so
- // that we don't get called back repeatedly. If we got an answer from the cache or /etc/hosts, we don't touch
- // RetryWithSearchDomains which may or may not be set.
- //
- // If we get e.g., NXDOMAIN and the query is neither suppressed nor exhausted the domain search list and
- // is a valid question for appending search domains, retry by appending domains
-
- if ((AddRecord != QC_suppressed) && question->SearchListIndex != -1 && question->AppendSearchDomains)
- {
- question->RetryWithSearchDomains = 0;
- result = AppendNewSearchDomain(question);
- // As long as the result is either zero or 1, we retry the question. If we exahaust the search
- // domains (result is zero) we try the original query (as it was before appending the search
- // domains) as such on the wire as a last resort if we have not tried them before. For queries
- // with more than one label, we have already tried them before appending search domains and
- // hence don't retry again
- if (result != -1)
+ else if (answer->dnssec_result == dnssec_bogus)
{
- mStatus err;
- err = mDNS_StartQuery(&mDNSStorage, question);
- if (!err)
- {
- LogOperation("%3d: RetryQuestionWithSearchDomains(%##s, %s), retrying after appending search domain", req->sd, question->qname.c, DNSTypeName(question->qtype));
- // If the result was zero, it meant that there are no search domains and we just retried the question
- // as a single label and we should not retry with search domains anymore.
- if (!result) question->SearchListIndex = -1;
- return mDNStrue;
- }
- else
- {
- LogMsg("%3d: ERROR: RetryQuestionWithSearchDomains %##s %s mDNS_StartQuery: %d, while retrying with search domains", req->sd, question->qname.c, DNSTypeName(question->qtype), (int)err);
- // We have already stopped the query and could not restart. Reset the appropriate pointers
- // so that we don't call stop again when the question terminates
- question->QuestionContext = mDNSNULL;
- }
+ flags |= kDNSServiceFlagsBogus;
+ dnssec_result_description = ", DNSSEC_Bogus";
}
+ else if (answer->dnssec_result == dnssec_indeterminate)
+ {
+ flags |= kDNSServiceFlagsIndeterminate;
+ dnssec_result_description = ", DNSSEC_Indeterminate";
+ }
+ } else if (question->DNSSECStatus.tried_dnssec_but_unsigned) {
+ // handle the case where we restart the question without the DNSSEC while the user requires DNSSEC result, for
+ // some reason we failed to get DNSSEC records. In which case, even if we go back to normal query, we should pass
+ // the DNSSEC result
+ flags |= kDNSServiceFlagsInsecure;
+ dnssec_result_description = ", DNSSEC_Insecure";
}
- else
- {
- LogDebug("%3d: RetryQuestionWithSearchDomains: Not appending search domains - SuppressQuery %d, SearchListIndex %d, AppendSearchDomains %d", req->sd, AddRecord, question->SearchListIndex, question->AppendSearchDomains);
- }
- return mDNSfalse;
-}
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
-mDNSlocal void queryrecord_result_reply(mDNS *const m, request_state *req, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord,
- DNSServiceErrorType error)
-{
- char name[MAX_ESCAPED_DOMAIN_NAME];
- size_t len;
- DNSServiceFlags flags = 0;
- reply_state *rep;
- char *data;
-
- ConvertDomainNameToCString(answer->name, name);
-
- LogOperation("%3d: %s(%##s, %s) RESULT %s interface %d: (%s)%s", req->sd,
- req->hdr.op == query_request ? "DNSServiceQueryRecord" : "DNSServiceGetAddrInfo",
- question->qname.c, DNSTypeName(question->qtype), AddRecord ? "ADD" : "RMV",
- mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID, mDNSfalse),
- MortalityDisplayString(answer->mortality), RRDisplayString(m, answer));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] DNSService" PUB_S "(" PRI_DM_NAME ", " PUB_S ") RESULT " PUB_S " interface %d: (" PUB_S PUB_S ")" PRI_S,
+ req->request_id, mDNSVal16(question->TargetQID), req->hdr.op == query_request ? "QueryRecord" : "GetAddrInfo",
+ DM_NAME_PARAM(&question->qname), DNSTypeName(question->qtype), AddRecord ? "ADD" : "RMV",
+ mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID, mDNSfalse),
+ MortalityDisplayString(answer->mortality), dnssec_result_description, RRDisplayString(m, answer));
len = sizeof(DNSServiceFlags); // calculate reply data length
len += sizeof(mDNSu32); // interface index
@@ -3203,30 +3593,8 @@ mDNSlocal void queryrecord_result_reply(mDNS *const m, request_state *req, DNSQu
flags |= kDNSServiceFlagsAdd;
if (answer->mortality == Mortality_Ghost)
flags |= kDNSServiceFlagsExpiredAnswer;
- if (question->ValidationStatus != 0)
- {
- error = kDNSServiceErr_NoError;
- if (question->ValidationRequired && question->ValidationState == DNSSECValDone)
- {
- switch (question->ValidationStatus) //Set the dnssec flags to be passed on to the Apps here
- {
- case DNSSEC_Secure:
- flags |= kDNSServiceFlagsSecure;
- break;
- case DNSSEC_Insecure:
- flags |= kDNSServiceFlagsInsecure;
- break;
- case DNSSEC_Indeterminate:
- flags |= kDNSServiceFlagsIndeterminate;
- break;
- case DNSSEC_Bogus:
- flags |= kDNSServiceFlagsBogus;
- break;
- default:
- LogMsg("queryrecord_result_reply unknown status %d for %##s", question->ValidationStatus, question->qname.c);
- }
- }
- }
+ if (!question->InitialCacheMiss)
+ flags |= kDNSServiceFlagAnsweredFromCache;
rep->rhdr->flags = dnssd_htonl(flags);
// Call mDNSPlatformInterfaceIndexfromInterfaceID, but suppressNetworkChange (last argument). Otherwise, if the
@@ -3254,507 +3622,280 @@ mDNSlocal void queryrecord_result_reply(mDNS *const m, request_state *req, DNSQu
put_uint32(AddRecord ? answer->rroriginalttl : 0, &data);
append_reply(req, rep);
- // Stop the question, if we just timed out
- if (error == kDNSServiceErr_Timeout)
- {
- mDNS_StopQuery(m, question);
- // Reset the pointers so that we don't call stop on termination
- question->QuestionContext = mDNSNULL;
- }
- else if ((AddRecord == QC_add) && req->hdr.op == addrinfo_request)
- {
- // Note: We count all answers including LocalOnly e.g., /etc/hosts. If we
- // exclude that, v4ans/v6ans will be zero and we would wrongly think that
- // we did not answer questions and setup the status to deliver triggers.
- if (question->qtype == kDNSType_A)
- req->u.addrinfo.v4ans = 1;
- if (question->qtype == kDNSType_AAAA)
- req->u.addrinfo.v6ans = 1;
- }
- else if ((AddRecord == QC_add) && req->hdr.op == query_request)
+}
+
+mDNSlocal void queryrecord_termination_callback(request_state *request)
+{
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u] DNSServiceQueryRecord(%X, %d, " PRI_DM_NAME ", " PUB_S ") STOP PID[%d](" PUB_S ")",
+ request->request_id, request->flags, request->interfaceIndex,
+ DM_NAME_PARAM(QueryRecordClientRequestGetQName(&request->u.queryrecord)),
+ DNSTypeName(QueryRecordClientRequestGetType(&request->u.queryrecord)), request->process_id, request->pid_name);
+
+ QueryRecordClientRequestStop(&request->u.queryrecord);
+}
+
+typedef struct {
+ char qname[MAX_ESCAPED_DOMAIN_NAME];
+ mDNSu32 interfaceIndex;
+ DNSServiceFlags flags;
+ mDNSu16 qtype;
+ mDNSu16 qclass;
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ mDNSBool require_privacy;
+#endif
+} _queryrecord_start_params_t;
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER) && MDNSRESPONDER_SUPPORTS(APPLE, IPC_TLV)
+mDNSlocal const mDNSu8 * ipc_tlv_get_resolver_config_plist_data(const mDNSu8 *const start, const mDNSu8 *const end,
+ size_t *outLen)
+{
+ size_t len = 0;
+ const mDNSu8 *value = NULL;
+ mdns_tlv16_get_value(start, end, IPC_TLV_TYPE_RESOLVER_CONFIG_PLIST_DATA, &len, &value, NULL);
+ if (outLen)
{
- if (question->qtype == kDNSType_A || question->qtype == kDNSType_AAAA)
- req->u.queryrecord.ans = 1;
+ *outLen = len;
}
+ return value;
+}
-#if APPLE_OSX_mDNSResponder
-#if !NO_WCF
- CHECK_WCF_FUNCTION(WCFIsServerRunning)
- {
- struct xucred x;
- socklen_t xucredlen = sizeof(x);
+mDNSlocal mDNSBool ipc_tlv_get_require_privacy(const mDNSu8 *const start, const mDNSu8 *const end)
+{
+ size_t len = 0;
+ const mDNSu8 *value = NULL;
+ mdns_tlv16_get_value(start, end, IPC_TLV_TYPE_REQUIRE_PRIVACY, &len, &value, NULL);
+ return ((len == 1) && (*value != 0)) ? mDNStrue : mDNSfalse;
+}
+#endif
- if (WCFIsServerRunning((WCFConnection *)m->WCF) && answer->rdlength != 0)
- {
- if (getsockopt(req->sd, 0, LOCAL_PEERCRED, &x, &xucredlen) >= 0 &&
- (x.cr_version == XUCRED_VERSION))
- {
- struct sockaddr_storage addr;
- addr.ss_len = 0;
- if (answer->rrtype == kDNSType_A || answer->rrtype == kDNSType_AAAA)
- {
- if (answer->rrtype == kDNSType_A)
- {
- struct sockaddr_in *const sin = (struct sockaddr_in *)&addr;
- sin->sin_port = 0;
- // Instead of this stupid call to putRData it would be much simpler to just assign the value in the sensible way, like this:
- // sin->sin_addr.s_addr = answer->rdata->u.ipv4.NotAnInteger;
- if (!putRData(mDNSNULL, (mDNSu8 *)&sin->sin_addr, (mDNSu8 *)(&sin->sin_addr + sizeof(mDNSv4Addr)), answer))
- LogMsg("queryrecord_result_reply: WCF AF_INET putRData failed");
- else
- {
- addr.ss_len = sizeof (struct sockaddr_in);
- addr.ss_family = AF_INET;
- }
- }
- else if (answer->rrtype == kDNSType_AAAA)
- {
- struct sockaddr_in6 *const sin6 = (struct sockaddr_in6 *)&addr;
- sin6->sin6_port = 0;
- // Instead of this stupid call to putRData it would be much simpler to just assign the value in the sensible way, like this:
- // sin6->sin6_addr.__u6_addr.__u6_addr32[0] = answer->rdata->u.ipv6.l[0];
- // sin6->sin6_addr.__u6_addr.__u6_addr32[1] = answer->rdata->u.ipv6.l[1];
- // sin6->sin6_addr.__u6_addr.__u6_addr32[2] = answer->rdata->u.ipv6.l[2];
- // sin6->sin6_addr.__u6_addr.__u6_addr32[3] = answer->rdata->u.ipv6.l[3];
- if (!putRData(mDNSNULL, (mDNSu8 *)&sin6->sin6_addr, (mDNSu8 *)(&sin6->sin6_addr + sizeof(mDNSv6Addr)), answer))
- LogMsg("queryrecord_result_reply: WCF AF_INET6 putRData failed");
- else
- {
- addr.ss_len = sizeof (struct sockaddr_in6);
- addr.ss_family = AF_INET6;
- }
- }
- if (addr.ss_len)
- {
- debugf("queryrecord_result_reply: Name %s, uid %u, addr length %d", name, x.cr_uid, addr.ss_len);
- CHECK_WCF_FUNCTION((WCFConnection *)WCFNameResolvesToAddr)
- {
- WCFNameResolvesToAddr(m->WCF, name, (struct sockaddr *)&addr, x.cr_uid);
- }
- }
- }
- else if (answer->rrtype == kDNSType_CNAME)
- {
- domainname cname;
- char cname_cstr[MAX_ESCAPED_DOMAIN_NAME];
- if (!putRData(mDNSNULL, cname.c, (mDNSu8 *)(cname.c + MAX_DOMAIN_NAME), answer))
- LogMsg("queryrecord_result_reply: WCF CNAME putRData failed");
- else
- {
- ConvertDomainNameToCString(&cname, cname_cstr);
- CHECK_WCF_FUNCTION((WCFConnection *)WCFNameResolvesToAddr)
- {
- WCFNameResolvesToName(m->WCF, name, cname_cstr, x.cr_uid);
- }
- }
- }
- }
- else my_perror("queryrecord_result_reply: ERROR: getsockopt LOCAL_PEERCRED");
- }
- }
+mDNSlocal mStatus _handle_queryrecord_request_start(request_state *request, const _queryrecord_start_params_t * const params)
+{
+ mStatus err;
+
+ request->terminate = queryrecord_termination_callback;
+
+ QueryRecordClientRequestParams queryParams;
+ QueryRecordClientRequestParamsInit(&queryParams);
+ queryParams.requestID = request->request_id;
+ queryParams.qnameStr = params->qname;
+ queryParams.interfaceIndex = params->interfaceIndex;
+ queryParams.flags = params->flags;
+ queryParams.qtype = params->qtype;
+ queryParams.qclass = params->qclass;
+ queryParams.effectivePID = request->validUUID ? 0 : request->process_id;
+ queryParams.effectiveUUID = request->validUUID ? request->uuid : mDNSNULL;
+ queryParams.peerUID = request->uid;
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ queryParams.needEncryption = params->require_privacy ? mDNStrue : mDNSfalse;
+ queryParams.customID = request->custom_service_id;
#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
+ queryParams.peerAuditToken = &request->audit_token;
#endif
+ err = QueryRecordClientRequestStart(&request->u.queryrecord, &queryParams, queryrecord_result_reply, request);
+ return err;
}
-mDNSlocal void queryrecord_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
+#if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
+
+mDNSlocal void _return_queryrecord_request_error(request_state * request, mStatus error)
{
- request_state *req = question->QuestionContext;
- DNSServiceErrorType error = kDNSServiceErr_NoError;
- DNSQuestion *q = mDNSNULL;
+ size_t len;
+ char * emptystr = "\0";
+ char * data;
+ reply_state *rep;
-#if APPLE_OSX_mDNSResponder
- {
- // Sanity check: QuestionContext is set to NULL after we stop the question and hence we should not
- // get any callbacks from the core after this.
- if (!req)
- {
- LogMsg("queryrecord_result_callback: ERROR!! QuestionContext NULL for %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
- return;
- }
- if (req->hdr.op == query_request && question == req->u.queryrecord.q2)
- q = &req->u.queryrecord.q;
- else if (req->hdr.op == addrinfo_request && question == req->u.addrinfo.q42)
- q = &req->u.addrinfo.q4;
- else if (req->hdr.op == addrinfo_request && question == req->u.addrinfo.q62)
- q = &req->u.addrinfo.q6;
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u] DNSService" PUB_S " _return_queryrecord_request_error: error(%d)",
+ request->request_id, request->hdr.op == query_request ? "QueryRecord" : "GetAddrInfo", error);
- if (q && question->qtype != q->qtype && !SameDomainName(&question->qname, &q->qname))
- {
- mStatus err;
- domainname *orig = question->qnameOrig;
-
- LogInfo("queryrecord_result_callback: Stopping q2 local %##s", question->qname.c);
- mDNS_StopQuery(m, question);
- question->QuestionContext = mDNSNULL;
-
- // We got a negative response for the SOA record indicating that .local does not exist.
- // But we might have other search domains (that does not end in .local) that can be
- // appended to this question. In that case, we want to retry the question. Otherwise,
- // we don't want to try this question as unicast.
- if (answer->RecordType == kDNSRecordTypePacketNegative && !q->AppendSearchDomains)
- {
- LogInfo("queryrecord_result_callback: question %##s AppendSearchDomains zero", q->qname.c);
- return;
- }
+ len = sizeof(DNSServiceFlags); // calculate reply data length
+ len += sizeof(mDNSu32); // interface index
+ len += sizeof(DNSServiceErrorType);
+ len += strlen(emptystr) + 1;
+ len += 3 * sizeof(mDNSu16); // type, class, rdlen
+ len += 0;//answer->rdlength;
+ len += sizeof(mDNSu32); // TTL
- // If we got a non-negative answer for our "local SOA" test query, start an additional parallel unicast query
- //
- // Note: When we copy the original question, we copy everything including the AppendSearchDomains,
- // RetryWithSearchDomains except for qnameOrig which can be non-NULL if the original question is
- // e.g., somehost and then we appended e.g., ".local" and retried that question. See comment in
- // SendAdditionalQuery as to how qnameOrig gets initialized.
- *question = *q;
- question->InterfaceID = mDNSInterface_Unicast;
- question->ExpectUnique = mDNStrue;
- question->qnameOrig = orig;
-
- LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) unicast, context %p", req->sd, question->qname.c, DNSTypeName(question->qtype), question->QuestionContext);
-
- // If the original question timed out, its QuestionContext would already be set to NULL and that's what we copied above.
- // Hence, we need to set it explicitly here.
- question->QuestionContext = req;
- err = mDNS_StartQuery(m, question);
- if (err) LogMsg("%3d: ERROR: queryrecord_result_callback %##s %s mDNS_StartQuery: %d", req->sd, question->qname.c, DNSTypeName(question->qtype), (int)err);
-
- // If we got a positive response to local SOA, then try the .local question as unicast
- if (answer->RecordType != kDNSRecordTypePacketNegative) return;
-
- // Fall through and get the next search domain. The question is pointing at .local
- // and we don't want to try that. Try the next search domain. Don't try with local
- // search domains for the unicast question anymore.
- //
- // Note: we started the question above which will be stopped immediately (never sent on the wire)
- // before we pick the next search domain below. RetryQuestionWithSearchDomains assumes that the
- // question has already started.
- question->AppendLocalSearchDomains = 0;
- }
-
- if (q && AddRecord && AddRecord != QC_dnssec && (question->InterfaceID == mDNSInterface_Unicast) && !answer->rdlength)
- {
- // If we get a negative response to the unicast query that we sent above, retry after appending search domains
- // Note: We could have appended search domains below (where do it for regular unicast questions) instead of doing it here.
- // As we ignore negative unicast answers below, we would never reach the code where the search domains are appended.
- // To keep things simple, we handle unicast ".local" separately here.
- LogInfo("queryrecord_result_callback: Retrying .local question %##s (%s) as unicast after appending search domains", question->qname.c, DNSTypeName(question->qtype));
- if (RetryQuestionWithSearchDomains(question, req, AddRecord))
- return;
- if (question->AppendSearchDomains && !question->AppendLocalSearchDomains && IsLocalDomain(&question->qname))
- {
- // If "local" is the last search domain, we need to stop the question so that we don't send the "local"
- // question on the wire as we got a negative response for the local SOA. But, we can't stop the question
- // yet as we may have to timeout the question (done by the "core") for which we need to leave the question
- // in the list. We leave it disabled so that it does not hit the wire.
- LogInfo("queryrecord_result_callback: Disabling .local question %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
- question->ThisQInterval = 0;
- }
- }
- // If we are here it means that either "question" is not "q2" OR we got a positive response for "q2" OR we have no more search
- // domains to append for "q2". In all cases, fall through and deliver the response
- }
-#endif // APPLE_OSX_mDNSResponder
+ rep = create_reply(request->hdr.op == query_request ? query_reply_op : addrinfo_reply_op, len, request);
- // If a query is being suppressed for some reason, we don't have to do any other
- // processing.
- //
- // Note: We don't check for "SuppressQuery" and instead use QC_suppressed because
- // the "core" needs to temporarily turn off SuppressQuery to answer this query.
- if (AddRecord == QC_suppressed)
+ rep->rhdr->flags = 0;
+ rep->rhdr->ifi = 0;
+ rep->rhdr->error = dnssd_htonl(error);
+
+ data = (char *)&rep->rhdr[1];
+
+ put_string(emptystr, &data);
+ put_uint16(0, &data);
+ put_uint16(0, &data);
+ put_uint16(0, &data);
+ data += 0;
+ put_uint32(0, &data);
+
+ append_reply(request, rep);
+}
+
+mDNSlocal mStatus _handle_queryrecord_request_with_trust(request_state *request, const _queryrecord_start_params_t * const params)
+{
+ mStatus err;
+ if (audit_token_to_pid(request->audit_token) == 0)
{
- LogDebug("queryrecord_result_callback: Suppressed question %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
- queryrecord_result_reply(m, req, question, answer, AddRecord, kDNSServiceErr_NoSuchRecord);
- return;
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_WARNING, "[R%u] _handle_queryrecord_request_with_trust: no audit token for pid(%s %d)", request->request_id, request->pid_name, request->process_id);
+ err = _handle_queryrecord_request_start(request, params);
}
-
- if (answer->RecordType == kDNSRecordTypePacketNegative)
+ else
{
- // If this question needs to be timed out and we have reached the stop time, mark
- // the error as timeout. It is possible that we might get a negative response from an
- // external DNS server at the same time when this question reaches its stop time. We
- // can't tell the difference as there is no indication in the callback. This should
- // be okay as we will be timing out this query anyway.
- mDNS_Lock(m);
- if (question->TimeoutQuestion)
+ const char *service_ptr = NULL;
+ char type_str[MAX_ESCAPED_DOMAIN_NAME] = "";
+ domainname query_name;
+ if (MakeDomainNameFromDNSNameString(&query_name, params->qname))
{
- if ((m->timenow - question->StopTime) >= 0)
+ domainlabel name;
+ domainname type, domain;
+ bool good = DeconstructServiceName(&query_name, &name, &type, &domain);
+ if (good)
{
- LogInfo("queryrecord_result_callback:Question %##s (%s) timing out, InterfaceID %p", question->qname.c, DNSTypeName(question->qtype), question->InterfaceID);
- error = kDNSServiceErr_Timeout;
+ ConvertDomainNameToCString(&type, type_str);
+ service_ptr = type_str;
}
}
- mDNS_Unlock(m);
- // When we're doing parallel unicast and multicast queries for dot-local names (for supporting Microsoft
- // Active Directory sites) we need to ignore negative unicast answers. Otherwise we'll generate negative
- // answers for just about every single multicast name we ever look up, since the Microsoft Active Directory
- // server is going to assert that pretty much every single multicast name doesn't exist.
- //
- // If we are timing out this query, we need to deliver the negative answer to the application
- if (error != kDNSServiceErr_Timeout)
+
+ mdns_trust_flags_t flags = mdns_trust_flags_none;
+ mdns_trust_status_t status = mdns_trust_check_query(request->audit_token, params->qname, service_ptr, params->qtype, (params->flags & kDNSServiceFlagsForceMulticast) != 0, &flags);
+ switch (status)
{
- if (!answer->InterfaceID && IsLocalDomain(answer->name))
+ case mdns_trust_status_denied:
+ case mdns_trust_status_pending:
{
- // Sanity check: "q" will be set only if "question" is the .local unicast query.
- if (!q)
+ mdns_trust_t trust = mdns_trust_create(request->audit_token, service_ptr, flags);
+ if (!trust )
{
- LogMsg("queryrecord_result_callback: ERROR!! answering multicast question %s with unicast cache record",
- RRDisplayString(m, answer));
- return;
+ err = mStatus_NoMemoryErr;
+ goto exit;
}
-#if APPLE_OSX_mDNSResponder
- if (!ShouldDeliverNegativeResponse(question))
+
+ void * context = mallocL("context/_handle_queryrecord_request_with_trust", sizeof(_queryrecord_start_params_t));
+ if (!context)
{
- return;
+ my_perror("ERROR: mallocL context/_handle_queryrecord_request_with_trust");
+ mdns_release(trust);
+ err = mStatus_NoMemoryErr;
+ goto exit;
}
-#endif // APPLE_OSX_mDNSResponder
- LogInfo("queryrecord_result_callback:Question %##s (%s) answering local with negative unicast response", question->qname.c,
- DNSTypeName(question->qtype));
- }
- error = kDNSServiceErr_NoSuchRecord;
- }
- }
- // If we get a negative answer, try appending search domains. Don't append search domains
- // - if we are timing out this question
- // - if the negative response was received as a result of a multicast query
- // - if this is an additional query (q2), we already appended search domains above (indicated by "!q" below)
- // - if this response is forced e.g., dnssec validation result
- if (error != kDNSServiceErr_Timeout)
- {
- if (!q && !answer->InterfaceID && !answer->rdlength && AddRecord && AddRecord != QC_dnssec)
- {
- // If the original question did not end in .local, we did not send an SOA query
- // to figure out whether we should send an additional unicast query or not. If we just
- // appended .local, we need to see if we need to send an additional query. This should
- // normally happen just once because after we append .local, we ignore all negative
- // responses for .local above.
- LogDebug("queryrecord_result_callback: Retrying question %##s (%s) after appending search domains", question->qname.c, DNSTypeName(question->qtype));
- if (RetryQuestionWithSearchDomains(question, req, AddRecord))
- {
- // Note: We need to call SendAdditionalQuery every time after appending a search domain as .local could
- // be anywhere in the search domain list.
-#if APPLE_OSX_mDNSResponder
- mStatus err = mStatus_NoError;
- err = SendAdditionalQuery(question, req, err);
- if (err) LogMsg("queryrecord_result_callback: Sending .local SOA query failed, after appending domains");
-#endif // APPLE_OSX_mDNSResponder
- return;
+ memcpy(context, params, sizeof(_queryrecord_start_params_t));
+ mdns_trust_set_context(trust, context);
+ mdns_trust_set_queue(trust, _get_trust_results_dispatch_queue());
+ mdns_trust_set_event_handler(trust, ^(mdns_trust_event_t event, mdns_trust_status_t update)
+ {
+ if (event == mdns_trust_event_result)
+ {
+ mStatus error = (update != mdns_trust_status_granted) ? mStatus_PolicyDenied : mStatus_NoError;
+ KQueueLock();
+ _queryrecord_start_params_t * _params = mdns_trust_get_context(trust);
+ if (_params)
+ {
+ if (!error)
+ {
+ error = _handle_queryrecord_request_start(request, _params);
+ // No context means the request was canceled before we got here
+ }
+ if (error) // (not else if) Always check for error result
+ {
+ _return_queryrecord_request_error(request, error);
+ }
+ }
+ KQueueUnlock("_handle_queryrecord_request_with_trust");
+ }
+ });
+ request->trust = trust;
+ mdns_trust_activate(trust);
+ err = mStatus_NoError;
+ break;
}
- }
- }
- queryrecord_result_reply(m, req, question, answer, AddRecord, error);
-}
-mDNSlocal void queryrecord_termination_callback(request_state *request)
-{
- LogOperation("%3d: DNSServiceQueryRecord(%X, %d, %##s, %s) STOP PID[%d](%s)",
- request->sd, request->flags, request->interfaceIndex, request->u.queryrecord.q.qname.c, DNSTypeName(request->u.queryrecord.q.qtype), request->process_id, request->pid_name);
- if (request->u.queryrecord.q.QuestionContext)
- {
- mDNS_StopQuery(&mDNSStorage, &request->u.queryrecord.q); // no need to error check
- LogMcastQ(&request->u.queryrecord.q, request, q_stop);
- request->u.queryrecord.q.QuestionContext = mDNSNULL;
- }
- else
- {
- DNSQuestion *question = &request->u.queryrecord.q;
- LogInfo("queryrecord_termination_callback: question %##s (%s) already stopped, InterfaceID %p", question->qname.c, DNSTypeName(question->qtype), question->InterfaceID);
- }
+ case mdns_trust_status_no_entitlement:
+ err = mStatus_NoAuth;
+ break;
- if (request->u.queryrecord.q.qnameOrig)
- {
- freeL("QueryTermination", request->u.queryrecord.q.qnameOrig);
- request->u.queryrecord.q.qnameOrig = mDNSNULL;
- }
+ case mdns_trust_status_granted:
+ err = _handle_queryrecord_request_start(request, params);
+ break;
- if (callExternalHelpers(request->u.queryrecord.q.InterfaceID, &request->u.queryrecord.q.qname, request->u.queryrecord.q.flags))
- {
- LogInfo("queryrecord_termination_callback: calling external_stop_browsing_for_service()");
- external_stop_browsing_for_service(request->u.queryrecord.q.InterfaceID, &request->u.queryrecord.q.qname, request->u.queryrecord.q.qtype, request->u.queryrecord.q.flags);
- }
- if (request->u.queryrecord.q2)
- {
- if (request->u.queryrecord.q2->QuestionContext)
- {
- LogInfo("queryrecord_termination_callback: Stopping q2 %##s", request->u.queryrecord.q2->qname.c);
- mDNS_StopQuery(&mDNSStorage, request->u.queryrecord.q2);
- LogMcastQ(request->u.queryrecord.q2, request, q_stop);
- }
- else
- {
- DNSQuestion *question = request->u.queryrecord.q2;
- LogInfo("queryrecord_termination_callback: q2 %##s (%s) already stopped, InterfaceID %p", question->qname.c, DNSTypeName(question->qtype), question->InterfaceID);
- }
- if (request->u.queryrecord.q2->qnameOrig)
- {
- LogInfo("queryrecord_termination_callback: freeing q2 qnameOrig %##s", request->u.queryrecord.q2->qnameOrig->c);
- freeL("QueryTermination q2", request->u.queryrecord.q2->qnameOrig);
- request->u.queryrecord.q2->qnameOrig = mDNSNULL;
- }
- freeL("queryrecord Q2", request->u.queryrecord.q2);
- request->u.queryrecord.q2 = mDNSNULL;
- }
-#if APPLE_OSX_mDNSResponder
- {
- if (request->u.queryrecord.ans)
- {
- DNSQuestion *v4q, *v6q;
- // If we are receiving poisitive answers, provide the hint to the
- // upper layer.
- v4q = v6q = mDNSNULL;
- if (request->u.queryrecord.q.qtype == kDNSType_A)
- v4q = &request->u.queryrecord.q;
- else if (request->u.queryrecord.q.qtype == kDNSType_AAAA)
- v6q = &request->u.queryrecord.q;
- mDNSPlatformTriggerDNSRetry(v4q, v6q);
+ default:
+ err = mStatus_UnknownErr;
+ break;
}
}
-#endif // APPLE_OSX_mDNSResponder
+exit:
+ return err;
}
+#endif // TRUST_ENFORCEMENT
mDNSlocal mStatus handle_queryrecord_request(request_state *request)
{
- DNSQuestion *const q = &request->u.queryrecord.q;
- char name[256];
- size_t nameLen;
- mDNSu16 rrtype, rrclass;
mStatus err;
+ _queryrecord_start_params_t params;
- DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
- mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
- mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
-
- // The request is scoped to a specific interface index, but the
- // interface is not currently in our list.
- if (interfaceIndex && !InterfaceID)
+ params.flags = get_flags(&request->msgptr, request->msgend);
+ params.interfaceIndex = get_uint32(&request->msgptr, request->msgend);
+ if (get_string(&request->msgptr, request->msgend, params.qname, sizeof(params.qname)) < 0)
{
- if (interfaceIndex > 1)
- LogMsg("handle_queryrecord_request: interfaceIndex %d is currently inactive requested by client[%d][%s]",
- interfaceIndex, request->process_id, request->pid_name);
- // If it's one of the specially defined inteface index values, just return an error.
- // Also, caller should return an error immediately if lo0 (index 1) is not configured
- // into the current active interfaces. See background in Radar 21967160.
- if (PreDefinedInterfaceIndex(interfaceIndex) || interfaceIndex == 1)
- {
- LogInfo("handle_queryrecord_request: bad interfaceIndex %d", interfaceIndex);
- return(mStatus_BadParamErr);
- }
-
- // Otherwise, use the specified interface index value and the request will
- // be applied to that interface when it comes up.
- InterfaceID = (mDNSInterfaceID)(uintptr_t)interfaceIndex;
- LogInfo("handle_queryrecord_request: query pending for interface index %d", interfaceIndex);
+ err = mStatus_BadParamErr;
+ goto exit;
}
-
- if (get_string(&request->msgptr, request->msgend, name, 256) < 0) return(mStatus_BadParamErr);
- rrtype = get_uint16(&request->msgptr, request->msgend);
- rrclass = get_uint16(&request->msgptr, request->msgend);
+ params.qtype = get_uint16(&request->msgptr, request->msgend);
+ params.qclass = get_uint16(&request->msgptr, request->msgend);
if (!request->msgptr)
- { LogMsg("%3d: DNSServiceQueryRecord(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
-
- request->flags = flags;
- request->interfaceIndex = interfaceIndex;
- mDNSPlatformMemZero(&request->u.queryrecord, sizeof(request->u.queryrecord));
-
- q->InterfaceID = InterfaceID;
- q->flags = flags;
- q->Target = zeroAddr;
- if (!MakeDomainNameFromDNSNameString(&q->qname, name)) return(mStatus_BadParamErr);
-#if 0
- if (!AuthorizedDomain(request, &q->qname, AutoBrowseDomains)) return (mStatus_NoError);
-#endif
- q->qtype = rrtype;
- q->qclass = rrclass;
- q->LongLived = (flags & kDNSServiceFlagsLongLivedQuery ) != 0;
- q->ExpectUnique = mDNSfalse;
- q->ForceMCast = (flags & kDNSServiceFlagsForceMulticast ) != 0;
- q->ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
- q->SuppressUnusable = (flags & kDNSServiceFlagsSuppressUnusable ) != 0;
- q->TimeoutQuestion = (flags & kDNSServiceFlagsTimeout ) != 0;
- q->allowExpired = (EnableAllowExpired && (flags & kDNSServiceFlagsAllowExpiredAnswers) != 0) ? AllowExpired_AllowExpiredAnswers : AllowExpired_None;
- q->WakeOnResolve = 0;
- q->UseBackgroundTrafficClass = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
- if ((flags & kDNSServiceFlagsValidate) != 0)
- q->ValidationRequired = DNSSEC_VALIDATION_SECURE;
- else if ((flags & kDNSServiceFlagsValidateOptional) != 0)
- q->ValidationRequired = DNSSEC_VALIDATION_SECURE_OPTIONAL;
- q->ValidatingResponse = 0;
- q->ProxyQuestion = 0;
- q->AnonInfo = mDNSNULL;
- q->QuestionCallback = queryrecord_result_callback;
- q->QuestionContext = request;
- q->SearchListIndex = 0;
- q->StopTime = 0;
-
- q->DNSSECAuthInfo = mDNSNULL;
- q->DAIFreeCallback = mDNSNULL;
-
- //Turn off dnssec validation for local domains and Question Types: RRSIG/ANY(ANY Type is not supported yet)
- if ((IsLocalDomain(&q->qname)) || (q->qtype == kDNSServiceType_RRSIG) || (q->qtype == kDNSServiceType_ANY))
- q->ValidationRequired = 0;
-
- // Don't append search domains for fully qualified domain names including queries
- // such as e.g., "abc." that has only one label. We convert all names to FQDNs as internally
- // we only deal with FQDNs. Hence, we cannot look at qname to figure out whether we should
- // append search domains or not. So, we record that information in AppendSearchDomains.
- //
- // We append search domains only for queries that are a single label. If overriden using command line
- // argument "AlwaysAppendSearchDomains", then we do it for any query which is not fully qualified.
- // For DNSSEC questions, append search domains only if kDNSServiceFlagsValidateOptional is set.
-
- nameLen = strlen(name);
- if ((!(q->ValidationRequired == DNSSEC_VALIDATION_SECURE)) && (!(q->ValidationRequired == DNSSEC_VALIDATION_INSECURE))
- && (rrtype == kDNSType_A || rrtype == kDNSType_AAAA) && ((nameLen == 0) || (name[nameLen - 1] != '.')) &&
- (AlwaysAppendSearchDomains || CountLabels(&q->qname) == 1))
{
- q->AppendSearchDomains = 1;
- q->AppendLocalSearchDomains = 1;
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%d] DNSServiceQueryRecord(unreadable parameters)", request->request_id);
+ err = mStatus_BadParamErr;
+ goto exit;
}
- else
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ params.require_privacy = mDNSfalse;
+#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER) && MDNSRESPONDER_SUPPORTS(APPLE, IPC_TLV)
+ if (request->msgptr && (request->hdr.ipc_flags & IPC_FLAGS_TRAILING_TLVS))
{
- q->AppendSearchDomains = 0;
- q->AppendLocalSearchDomains = 0;
+ size_t len;
+ const mDNSu8 *const start = (const mDNSu8 *)request->msgptr;
+ const mDNSu8 *const end = (const mDNSu8 *)request->msgend;
+ const mDNSu8 *const data = ipc_tlv_get_resolver_config_plist_data(start, end, &len);
+ if (data)
+ {
+ request->custom_service_id = Querier_RegisterCustomDNSServiceWithPListData(data, len);
+ }
+ params.require_privacy = ipc_tlv_get_require_privacy(start, end);
}
+#endif
+ request->flags = params.flags;
+ request->interfaceIndex = params.interfaceIndex;
- // For single label queries that are not fully qualified, look at /etc/hosts, cache and try
- // search domains before trying them on the wire as a single label query. RetryWithSearchDomains
- // tell the core to call back into the UDS layer if there is no valid response in /etc/hosts or
- // the cache
- q->RetryWithSearchDomains = ApplySearchDomainsFirst(q) ? 1 : 0;
- q->qnameOrig = mDNSNULL;
- SetQuestionPolicy(q, request);
-
-#if APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
- // Determine if this request should be promoted to use BLE triggered discovery.
- if (shouldUseBLE(InterfaceID, rrtype, (domainname *)SkipLeadingLabels(&q->qname, 1), &q->qname))
- {
- q->flags |= (kDNSServiceFlagsAutoTrigger | kDNSServiceFlagsIncludeAWDL);
- request->flags |= (kDNSServiceFlagsAutoTrigger | kDNSServiceFlagsIncludeAWDL);
- LogInfo("handle_queryrecord_request: request promoted to use kDNSServiceFlagsAutoTrigger");
- }
-#endif // APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceQueryRecord(%X, %d, " PRI_S ", " PUB_S ") START PID[%d](" PUB_S ")",
+ request->request_id, request->flags, request->interfaceIndex, params.qname, DNSTypeName(params.qtype), request->process_id,
+ request->pid_name);
- LogOperation("%3d: DNSServiceQueryRecord(%X, %d, %##s, %s) START PID[%d](%s)",
- request->sd, request->flags, interfaceIndex, q->qname.c, DNSTypeName(q->qtype), request->process_id, request->pid_name);
- err = mDNS_StartQuery(&mDNSStorage, q);
+ mDNSPlatformMemZero(&request->u.queryrecord, (mDNSu32)sizeof(request->u.queryrecord));
+ request->terminate = NULL;
- if (err)
+#if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
+ if (os_feature_enabled(mDNSResponder, bonjour_privacy))
{
- LogMsg("%3d: ERROR: DNSServiceQueryRecord %##s %s mDNS_StartQuery: %d", request->sd, q->qname.c, DNSTypeName(q->qtype), (int)err);
+ err = _handle_queryrecord_request_with_trust(request, &params);
}
else
{
- request->terminate = queryrecord_termination_callback;
- LogMcastQ(q, request, q_start);
- if (callExternalHelpers(q->InterfaceID, &q->qname, q->flags))
- {
- LogDebug("handle_queryrecord_request: calling external_start_browsing_for_service()");
- external_start_browsing_for_service(q->InterfaceID, &q->qname, q->qtype, q->flags);
- }
+ err = _handle_queryrecord_request_start(request, &params);
}
+#else
+ err = _handle_queryrecord_request_start(request, &params);
+#endif
-#if APPLE_OSX_mDNSResponder
- err = SendAdditionalQuery(q, request, err);
-#endif // APPLE_OSX_mDNSResponder
-
+exit:
return(err);
}
@@ -3835,7 +3976,10 @@ mDNSlocal void enum_result_callback(mDNS *const m,
reply = format_enumeration_reply(request, domain, flags, kDNSServiceInterfaceIndexAny, kDNSServiceErr_NoError);
if (!reply) { LogMsg("ERROR: enum_result_callback, format_enumeration_reply"); return; }
- LogOperation("%3d: DNSServiceEnumerateDomains(%#2s) RESULT %s: %s", request->sd, question->qname.c, AddRecord ? "ADD" : "RMV", domain);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d->Q%d] DNSServiceEnumerateDomains(%2.*s) RESULT " PUB_S ": " PRI_S,
+ request->request_id, mDNSVal16(question->TargetQID), question->qname.c[0], &question->qname.c[1],
+ AddRecord ? "ADD" : "RMV", domain);
append_reply(request, reply);
}
@@ -3943,9 +4087,9 @@ mDNSlocal mStatus handle_release_request(request_state *request)
// extract the data from the message
DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
- if (get_string(&request->msgptr, request->msgend, name, 256) < 0 ||
- get_string(&request->msgptr, request->msgend, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
- get_string(&request->msgptr, request->msgend, domain, MAX_ESCAPED_DOMAIN_NAME) < 0)
+ if (get_string(&request->msgptr, request->msgend, name, sizeof(name )) < 0 ||
+ get_string(&request->msgptr, request->msgend, regtype, sizeof(regtype)) < 0 ||
+ get_string(&request->msgptr, request->msgend, domain, sizeof(domain )) < 0)
{
LogMsg("ERROR: handle_release_request - Couldn't read name/regtype/domain");
return(mStatus_BadParamErr);
@@ -3963,10 +4107,13 @@ mDNSlocal mStatus handle_release_request(request_state *request)
return(mStatus_BadParamErr);
}
- LogOperation("%3d: PeerConnectionRelease(%X %##s) START PID[%d](%s)",
- request->sd, flags, instance.c, request->process_id, request->pid_name);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] PeerConnectionRelease(%X " PRI_DM_NAME ") START PID[%d](" PUB_S ")",
+ request->request_id, flags, DM_NAME_PARAM(&instance), request->process_id, request->pid_name);
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
external_connection_release(&instance);
+#endif
return(err);
}
@@ -3986,7 +4133,7 @@ mDNSlocal mStatus handle_setdomain_request(request_state *request)
domainname domain;
DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
(void)flags; // Unused
- if (get_string(&request->msgptr, request->msgend, domainstr, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
+ if (get_string(&request->msgptr, request->msgend, domainstr, sizeof(domainstr)) < 0 ||
!MakeDomainNameFromDNSNameString(&domain, domainstr))
{ LogMsg("%3d: DNSServiceSetDefaultDomainForUser(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
@@ -4007,7 +4154,8 @@ mDNSlocal void handle_getproperty_request(request_state *request)
char prop[256];
if (get_string(&request->msgptr, request->msgend, prop, sizeof(prop)) >= 0)
{
- LogOperation("%3d: DNSServiceGetProperty(%s)", request->sd, prop);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceGetProperty(" PUB_S ")", request->request_id, prop);
if (!strcmp(prop, kDNSServiceProperty_DaemonVersion))
{
DaemonVersionReply x = { 0, dnssd_htonl(4), dnssd_htonl(_DNS_SD_H) };
@@ -4029,8 +4177,9 @@ mDNSlocal void handle_connection_delegate_request(request_state *request)
mDNSs32 pid;
socklen_t len;
- LogOperation("%3d: DNSServiceCreateDelegateConnection START PID[%d](%s)",
- request->sd, request->process_id, request->pid_name);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceCreateDelegateConnection START PID[%d](" PUB_S ")",
+ request->request_id, request->process_id, request->pid_name);
request->terminate = connection_termination;
len = 0;
@@ -4077,63 +4226,6 @@ typedef packedstruct
mDNSs32 pid;
} PIDInfo;
-mDNSlocal void handle_getpid_request(request_state *request)
-{
- const request_state *req;
- mDNSs32 pid = -1;
- mDNSu16 srcport = get_uint16(&request->msgptr, request->msgend);
- const DNSQuestion *q = NULL;
- PIDInfo pi;
-
- LogMsg("%3d: DNSServiceGetPID START", request->sd);
-
- for (req = all_requests; req; req=req->next)
- {
- if (req->hdr.op == query_request)
- q = &req->u.queryrecord.q;
- else if (req->hdr.op == addrinfo_request)
- q = &req->u.addrinfo.q4;
- else if (req->hdr.op == addrinfo_request)
- q = &req->u.addrinfo.q6;
-
- if (q && q->LocalSocket != NULL)
- {
- mDNSu16 port = mDNSPlatformGetUDPPort(q->LocalSocket);
- if (port == srcport)
- {
- pid = req->process_id;
- LogMsg("DNSServiceGetPID: srcport %d, pid %d [%s] question %##s", htons(srcport), pid, req->pid_name, q->qname.c);
- break;
- }
- }
- }
- // If we cannot find in the client requests, look to see if this was
- // started by mDNSResponder.
- if (pid == -1)
- {
- for (q = mDNSStorage.Questions; q; q = q->next)
- {
- if (q && q->LocalSocket != NULL)
- {
- mDNSu16 port = mDNSPlatformGetUDPPort(q->LocalSocket);
- if (port == srcport)
- {
-#if APPLE_OSX_mDNSResponder
- pid = getpid();
-#endif // APPLE_OSX_mDNSResponder
- LogMsg("DNSServiceGetPID: srcport %d, pid %d [%s], question %##s", htons(srcport), pid, "_mDNSResponder", q->qname.c);
- break;
- }
- }
- }
- }
-
- pi.err = 0;
- pi.pid = pid;
- send_all(request->sd, (const char *)&pi, sizeof(PIDInfo));
- LogMsg("%3d: DNSServiceGetPID STOP", request->sd);
-}
-
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
@@ -4144,10 +4236,11 @@ mDNSlocal void handle_getpid_request(request_state *request)
mDNSlocal void port_mapping_termination_callback(request_state *request)
{
- LogOperation("%3d: DNSServiceNATPortMappingCreate(%X, %u, %u, %d) STOP PID[%d](%s)", request->sd,
- DNSServiceProtocol(request->u.pm.NATinfo.Protocol),
- mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt), request->u.pm.NATinfo.NATLease,
- request->process_id, request->pid_name);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%d] DNSServiceNATPortMappingCreate(%X, %u, %u, %d) STOP PID[%d](" PUB_S ")",
+ request->request_id, DNSServiceProtocol(request->u.pm.NATinfo.Protocol),
+ mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt), request->u.pm.NATinfo.NATLease,
+ request->process_id, request->pid_name);
+
mDNS_StopNATOperation(&mDNSStorage, &request->u.pm.NATinfo);
}
@@ -4187,10 +4280,12 @@ mDNSlocal void port_mapping_create_request_callback(mDNS *m, NATTraversalInfo *n
*data++ = request->u.pm.NATinfo.ExternalPort.b[1];
put_uint32(request->u.pm.NATinfo.Lifetime, &data);
- LogOperation("%3d: DNSServiceNATPortMappingCreate(%X, %u, %u, %d) RESULT %.4a:%u TTL %u", request->sd,
- DNSServiceProtocol(request->u.pm.NATinfo.Protocol),
- mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt), request->u.pm.NATinfo.NATLease,
- &request->u.pm.NATinfo.ExternalAddress, mDNSVal16(request->u.pm.NATinfo.ExternalPort), request->u.pm.NATinfo.Lifetime);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceNATPortMappingCreate(%X, %u, %u, %d) RESULT " PRI_IPv4_ADDR ":%u TTL %u",
+ request->request_id, DNSServiceProtocol(request->u.pm.NATinfo.Protocol),
+ mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt), request->u.pm.NATinfo.NATLease,
+ &request->u.pm.NATinfo.ExternalAddress, mDNSVal16(request->u.pm.NATinfo.ExternalPort),
+ request->u.pm.NATinfo.Lifetime);
append_reply(request, rep);
}
@@ -4217,7 +4312,11 @@ mDNSlocal mStatus handle_port_mapping_request(request_state *request)
}
if (!request->msgptr)
- { LogMsg("%3d: DNSServiceNATPortMappingCreate(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%d] DNSServiceNATPortMappingCreate(unreadable parameters)", request->request_id);
+ return(mStatus_BadParamErr);
+ }
if (protocol == 0) // If protocol == 0 (i.e. just request public address) then IntPort, ExtPort, ttl must be zero too
{
@@ -4238,9 +4337,10 @@ mDNSlocal mStatus handle_port_mapping_request(request_state *request)
request->u.pm.NATinfo.clientCallback = port_mapping_create_request_callback;
request->u.pm.NATinfo.clientContext = request;
- LogOperation("%3d: DNSServiceNATPortMappingCreate(%X, %u, %u, %d) START PID[%d](%s)", request->sd,
- protocol, mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt), request->u.pm.NATinfo.NATLease,
- request->process_id, request->pid_name);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceNATPortMappingCreate(%X, %u, %u, %d) START PID[%d](" PUB_S ")",
+ request->request_id, protocol, mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt),
+ request->u.pm.NATinfo.NATLease, request->process_id, request->pid_name);
err = mDNS_StartNATOperation(&mDNSStorage, &request->u.pm.NATinfo);
if (err) LogMsg("ERROR: mDNS_StartNATOperation: %d", (int)err);
else request->terminate = port_mapping_termination_callback;
@@ -4256,319 +4356,201 @@ mDNSlocal mStatus handle_port_mapping_request(request_state *request)
mDNSlocal void addrinfo_termination_callback(request_state *request)
{
- LogOperation("%3d: DNSServiceGetAddrInfo(%##s) STOP PID[%d](%s)", request->sd, request->u.addrinfo.q4.qname.c,
- request->process_id, request->pid_name);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u] DNSServiceGetAddrInfo(" PRI_DM_NAME ") STOP PID[%d](" PUB_S ")",
+ request->request_id, DM_NAME_PARAM(GetAddrInfoClientRequestGetQName(&request->u.addrinfo)),
+ request->process_id, request->pid_name);
- if (request->u.addrinfo.q4.QuestionContext)
- {
- mDNS_StopQuery(&mDNSStorage, &request->u.addrinfo.q4);
- LogMcastQ(&request->u.addrinfo.q4, request, q_stop);
- request->u.addrinfo.q4.QuestionContext = mDNSNULL;
+ GetAddrInfoClientRequestStop(&request->u.addrinfo);
+}
- if (callExternalHelpers(request->u.addrinfo.interface_id, &request->u.addrinfo.q4.qname, request->flags))
- {
- LogInfo("addrinfo_termination_callback: calling external_stop_browsing_for_service() for A record");
- external_stop_browsing_for_service(request->u.addrinfo.interface_id, &request->u.addrinfo.q4.qname, kDNSServiceType_A, request->flags);
- }
- }
- if (request->u.addrinfo.q4.qnameOrig)
- {
- freeL("QueryTermination", request->u.addrinfo.q4.qnameOrig);
- request->u.addrinfo.q4.qnameOrig = mDNSNULL;
- }
- if (request->u.addrinfo.q42)
- {
- if (request->u.addrinfo.q42->QuestionContext)
- {
- LogInfo("addrinfo_termination_callback: Stopping q42 %##s", request->u.addrinfo.q42->qname.c);
- mDNS_StopQuery(&mDNSStorage, request->u.addrinfo.q42);
- LogMcastQ(request->u.addrinfo.q42, request, q_stop);
- }
- if (request->u.addrinfo.q42->qnameOrig)
- {
- LogInfo("addrinfo_termination_callback: freeing q42 qnameOrig %##s", request->u.addrinfo.q42->qnameOrig->c);
- freeL("QueryTermination q42", request->u.addrinfo.q42->qnameOrig);
- request->u.addrinfo.q42->qnameOrig = mDNSNULL;
- }
- freeL("addrinfo Q42", request->u.addrinfo.q42);
- request->u.addrinfo.q42 = mDNSNULL;
- }
+typedef struct {
+ mDNSu32 protocols;
+ char hostname[MAX_ESCAPED_DOMAIN_NAME];
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ mDNSBool require_privacy;
+#endif
+} _addrinfo_start_params_t;
- if (request->u.addrinfo.q6.QuestionContext)
- {
- mDNS_StopQuery(&mDNSStorage, &request->u.addrinfo.q6);
- LogMcastQ(&request->u.addrinfo.q6, request, q_stop);
- request->u.addrinfo.q6.QuestionContext = mDNSNULL;
+mDNSlocal mStatus _handle_addrinfo_request_start(request_state *request, const _addrinfo_start_params_t * const params)
+{
+ mStatus err;
- if (callExternalHelpers(request->u.addrinfo.interface_id, &request->u.addrinfo.q6.qname, request->flags))
- {
- LogInfo("addrinfo_termination_callback: calling external_stop_browsing_for_service() for AAAA record");
- external_stop_browsing_for_service(request->u.addrinfo.interface_id, &request->u.addrinfo.q6.qname, kDNSServiceType_AAAA, request->flags);
- }
- }
- if (request->u.addrinfo.q6.qnameOrig)
- {
- freeL("QueryTermination", request->u.addrinfo.q6.qnameOrig);
- request->u.addrinfo.q6.qnameOrig = mDNSNULL;
- }
- if (request->u.addrinfo.q62)
+ request->terminate = addrinfo_termination_callback;
+
+ GetAddrInfoClientRequestParams gaiParams;
+ GetAddrInfoClientRequestParamsInit(&gaiParams);
+ gaiParams.requestID = request->request_id;
+ gaiParams.hostnameStr = params->hostname;
+ gaiParams.interfaceIndex = request->interfaceIndex;
+ gaiParams.flags = request->flags;
+ gaiParams.protocols = params->protocols;
+ gaiParams.effectivePID = request->validUUID ? 0 : request->process_id;
+ gaiParams.effectiveUUID = request->validUUID ? request->uuid : mDNSNULL;
+ gaiParams.peerUID = request->uid;
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ gaiParams.needEncryption = params->require_privacy ? mDNStrue : mDNSfalse;
+ gaiParams.customID = request->custom_service_id;
+#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
+ gaiParams.peerAuditToken = &request->audit_token;
+#endif
+ err = GetAddrInfoClientRequestStart(&request->u.addrinfo, &gaiParams, queryrecord_result_reply, request);
+
+ return err;
+}
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
+
+mDNSlocal void _return_addrinfo_request_error(request_state * request, mStatus error)
+{
+ _return_queryrecord_request_error(request, error);
+}
+
+mDNSlocal mStatus _handle_addrinfo_request_with_trust(request_state *request, const _addrinfo_start_params_t * const params)
+{
+ mStatus err;
+ if (audit_token_to_pid(request->audit_token) == 0)
{
- if (request->u.addrinfo.q62->QuestionContext)
- {
- LogInfo("addrinfo_termination_callback: Stopping q62 %##s", request->u.addrinfo.q62->qname.c);
- mDNS_StopQuery(&mDNSStorage, request->u.addrinfo.q62);
- LogMcastQ(request->u.addrinfo.q62, request, q_stop);
- }
- if (request->u.addrinfo.q62->qnameOrig)
- {
- LogInfo("addrinfo_termination_callback: freeing q62 qnameOrig %##s", request->u.addrinfo.q62->qnameOrig->c);
- freeL("QueryTermination q62", request->u.addrinfo.q62->qnameOrig);
- request->u.addrinfo.q62->qnameOrig = mDNSNULL;
- }
- freeL("addrinfo Q62", request->u.addrinfo.q62);
- request->u.addrinfo.q62 = mDNSNULL;
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_WARNING, "[R%u] _handle_addrinfo_request_with_trust: no audit token for pid(%s %d)", request->request_id, request->pid_name, request->process_id);
+ err = _handle_addrinfo_request_start(request, params);
}
-#if APPLE_OSX_mDNSResponder
+ else
{
- DNSQuestion *v4q, *v6q;
- v4q = v6q = mDNSNULL;
- if (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv4)
- {
- // If we are not delivering answers, we may be timing out prematurely.
- // Note down the current state so that we know to retry when we see a
- // valid response again.
- if (request->u.addrinfo.q4.TimeoutQuestion && !request->u.addrinfo.v4ans)
- {
- mDNSPlatformUpdateDNSStatus(&request->u.addrinfo.q4);
- }
- // If we have a v4 answer and if we timed out prematurely before, provide
- // a trigger to the upper layer so that it can retry questions if needed.
- if (request->u.addrinfo.v4ans)
- v4q = &request->u.addrinfo.q4;
- }
- if (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv6)
+ mdns_trust_flags_t flags = mdns_trust_flags_none;
+ mdns_trust_status_t status = mdns_trust_check_getaddrinfo(request->audit_token, params->hostname, &flags);
+ switch (status)
{
- if (request->u.addrinfo.q6.TimeoutQuestion && !request->u.addrinfo.v6ans)
+ case mdns_trust_status_denied:
+ case mdns_trust_status_pending:
{
- mDNSPlatformUpdateDNSStatus(&request->u.addrinfo.q6);
+ mdns_trust_t trust = mdns_trust_create(request->audit_token, NULL, flags);
+ if (!trust )
+ {
+ err = mStatus_NoMemoryErr;
+ goto exit;
+ }
+
+ void * context = mallocL("context/_handle_addrinfo_request_with_trust", sizeof(_addrinfo_start_params_t));
+ if (!context)
+ {
+ my_perror("ERROR: mallocL context/_handle_addrinfo_request_with_trust");
+ mdns_release(trust);
+ err = mStatus_NoMemoryErr;
+ goto exit;
+ }
+ memcpy(context, params, sizeof(_addrinfo_start_params_t));
+ mdns_trust_set_context(trust, context);
+ mdns_trust_set_queue(trust, _get_trust_results_dispatch_queue());
+ mdns_trust_set_event_handler(trust, ^(mdns_trust_event_t event, mdns_trust_status_t update)
+ {
+ if (event == mdns_trust_event_result)
+ {
+ mStatus error = (update != mdns_trust_status_granted) ? mStatus_PolicyDenied : mStatus_NoError;
+ KQueueLock();
+ _addrinfo_start_params_t * _params = mdns_trust_get_context(trust);
+ if (_params)
+ {
+ if (!error)
+ {
+ error = _handle_addrinfo_request_start(request, _params);
+ // No context means the request was canceled before we got here
+ }
+ if (error) // (not else if) Always check for error result
+ {
+ _return_addrinfo_request_error(request, error);
+ }
+ }
+ KQueueUnlock("_handle_addrinfo_request_with_trust");
+ }
+ });
+ request->trust = trust;
+ mdns_trust_activate(trust);
+ err = mStatus_NoError;
+ break;
}
- if (request->u.addrinfo.v6ans)
- v6q = &request->u.addrinfo.q6;
+
+ case mdns_trust_status_no_entitlement:
+ err = mStatus_NoAuth;
+ break;
+
+ case mdns_trust_status_granted:
+ err = _handle_addrinfo_request_start(request, params);
+ break;
+
+ default:
+ err = mStatus_UnknownErr;
+ break;
}
- mDNSPlatformTriggerDNSRetry(v4q, v6q);
}
-#endif // APPLE_OSX_mDNSResponder
+exit:
+ return err;
}
+#endif // TRUST_ENFORCEMENT
mDNSlocal mStatus handle_addrinfo_request(request_state *request)
{
- char hostname[256];
- size_t hostnameLen;
- domainname d;
- mStatus err = 0;
- mDNSs32 serviceIndex = -1; // default unscoped value for ServiceID is -1
- mDNSInterfaceID InterfaceID;
-
- DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
-
- mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
+ mStatus err;
+ DNSServiceFlags flags;
+ mDNSu32 interfaceIndex;
+ _addrinfo_start_params_t params;
- if (flags & kDNSServiceFlagsServiceIndex)
+ flags = get_flags(&request->msgptr, request->msgend);
+ interfaceIndex = get_uint32(&request->msgptr, request->msgend);
+ params.protocols = get_uint32(&request->msgptr, request->msgend);
+ if (get_string(&request->msgptr, request->msgend, params.hostname, sizeof(params.hostname)) < 0)
{
- // NOTE: kDNSServiceFlagsServiceIndex flag can only be set for DNSServiceGetAddrInfo()
- LogInfo("DNSServiceGetAddrInfo: kDNSServiceFlagsServiceIndex is SET by the client");
- // if kDNSServiceFlagsServiceIndex is SET,
- // interpret the interfaceID as the serviceId and set the interfaceID to 0.
- serviceIndex = interfaceIndex;
- interfaceIndex = 0;
+ err = mStatus_BadParamErr;
+ goto exit;
}
-
- mDNSPlatformMemZero(&request->u.addrinfo, sizeof(request->u.addrinfo));
-
- InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
-
- // The request is scoped to a specific interface index, but the
- // interface is not currently in our list.
- if (interfaceIndex && !InterfaceID)
+ if (!request->msgptr)
{
- if (interfaceIndex > 1)
- LogMsg("handle_addrinfo_request: interfaceIndex %d is currently inactive requested by client[%d][%s]",
- interfaceIndex, request->process_id, request->pid_name);
- // If it's one of the specially defined inteface index values, just return an error.
- if (PreDefinedInterfaceIndex(interfaceIndex))
- {
- LogInfo("handle_addrinfo_request: bad interfaceIndex %d", interfaceIndex);
- return(mStatus_BadParamErr);
- }
-
- // Otherwise, use the specified interface index value and the request will
- // be applied to that interface when it comes up.
- InterfaceID = (mDNSInterfaceID)(uintptr_t)interfaceIndex;
- LogInfo("handle_addrinfo_request: query pending for interface index %d", interfaceIndex);
+ LogMsg("%3d: DNSServiceGetAddrInfo(unreadable parameters)", request->sd);
+ err = mStatus_BadParamErr;
+ goto exit;
}
-
- request->flags = flags;
- request->interfaceIndex = interfaceIndex;
- request->u.addrinfo.interface_id = InterfaceID;
- request->u.addrinfo.flags = flags;
- request->u.addrinfo.protocol = get_uint32(&request->msgptr, request->msgend);
-
- if (request->u.addrinfo.protocol > (kDNSServiceProtocol_IPv4|kDNSServiceProtocol_IPv6)) return(mStatus_BadParamErr);
-
- if (get_string(&request->msgptr, request->msgend, hostname, 256) < 0) return(mStatus_BadParamErr);
-
- if (!request->msgptr) { LogMsg("%3d: DNSServiceGetAddrInfo(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
-
- if (!MakeDomainNameFromDNSNameString(&d, hostname))
- { LogMsg("ERROR: handle_addrinfo_request: bad hostname: %s", hostname); return(mStatus_BadParamErr); }
-
-#if 0
- if (!AuthorizedDomain(request, &d, AutoBrowseDomains)) return (mStatus_NoError);
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ params.require_privacy = mDNSfalse;
#endif
-
- if (!request->u.addrinfo.protocol)
- {
- flags |= kDNSServiceFlagsSuppressUnusable;
- request->u.addrinfo.protocol = (kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6);
- }
-
- request->u.addrinfo.q4.InterfaceID = request->u.addrinfo.q6.InterfaceID = request->u.addrinfo.interface_id;
- request->u.addrinfo.q4.ServiceID = request->u.addrinfo.q6.ServiceID = serviceIndex;
- request->u.addrinfo.q4.flags = request->u.addrinfo.q6.flags = flags;
- request->u.addrinfo.q4.Target = request->u.addrinfo.q6.Target = zeroAddr;
- request->u.addrinfo.q4.qname = request->u.addrinfo.q6.qname = d;
- request->u.addrinfo.q4.qclass = request->u.addrinfo.q6.qclass = kDNSServiceClass_IN;
- request->u.addrinfo.q4.LongLived = request->u.addrinfo.q6.LongLived = (flags & kDNSServiceFlagsLongLivedQuery ) != 0;
- request->u.addrinfo.q4.ExpectUnique = request->u.addrinfo.q6.ExpectUnique = mDNSfalse;
- request->u.addrinfo.q4.ForceMCast = request->u.addrinfo.q6.ForceMCast = (flags & kDNSServiceFlagsForceMulticast ) != 0;
- request->u.addrinfo.q4.ReturnIntermed = request->u.addrinfo.q6.ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
- request->u.addrinfo.q4.SuppressUnusable = request->u.addrinfo.q6.SuppressUnusable = (flags & kDNSServiceFlagsSuppressUnusable ) != 0;
- request->u.addrinfo.q4.TimeoutQuestion = request->u.addrinfo.q6.TimeoutQuestion = (flags & kDNSServiceFlagsTimeout ) != 0;
- request->u.addrinfo.q4.allowExpired = request->u.addrinfo.q6.allowExpired = (EnableAllowExpired && (flags & kDNSServiceFlagsAllowExpiredAnswers) != 0) ? AllowExpired_AllowExpiredAnswers : AllowExpired_None;
- request->u.addrinfo.q4.WakeOnResolve = request->u.addrinfo.q6.WakeOnResolve = 0;
- request->u.addrinfo.q4.UseBackgroundTrafficClass = request->u.addrinfo.q6.UseBackgroundTrafficClass = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
- if ((flags & kDNSServiceFlagsValidate) != 0)
- request->u.addrinfo.q4.ValidationRequired = request->u.addrinfo.q6.ValidationRequired = DNSSEC_VALIDATION_SECURE;
- else if ((flags & kDNSServiceFlagsValidateOptional) != 0)
- request->u.addrinfo.q4.ValidationRequired = request->u.addrinfo.q6.ValidationRequired = DNSSEC_VALIDATION_SECURE_OPTIONAL;
- request->u.addrinfo.q4.ValidatingResponse = request->u.addrinfo.q6.ValidatingResponse = 0;
- request->u.addrinfo.q4.ProxyQuestion = request->u.addrinfo.q6.ProxyQuestion = 0;
- request->u.addrinfo.q4.qnameOrig = request->u.addrinfo.q6.qnameOrig = mDNSNULL;
- request->u.addrinfo.q4.AnonInfo = request->u.addrinfo.q6.AnonInfo = mDNSNULL;
-
- SetQuestionPolicy(&request->u.addrinfo.q4, request);
- SetQuestionPolicy(&request->u.addrinfo.q6, request);
-
- request->u.addrinfo.q4.StopTime = request->u.addrinfo.q6.StopTime = 0;
-
- request->u.addrinfo.q4.DNSSECAuthInfo = request->u.addrinfo.q6.DNSSECAuthInfo = mDNSNULL;
- request->u.addrinfo.q4.DAIFreeCallback = request->u.addrinfo.q6.DAIFreeCallback = mDNSNULL;
-
- //Turn off dnssec validation for local domains
- if (IsLocalDomain(&d))
- request->u.addrinfo.q4.ValidationRequired = request->u.addrinfo.q6.ValidationRequired = 0;
-
- hostnameLen = strlen(hostname);
-
- LogOperation("%3d: DNSServiceGetAddrInfo(%X, %d, %d, %##s) START PID[%d](%s)",
- request->sd, flags, interfaceIndex, request->u.addrinfo.protocol, d.c, request->process_id, request->pid_name);
-
- if (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv6)
- {
- request->u.addrinfo.q6.qtype = kDNSServiceType_AAAA;
- request->u.addrinfo.q6.SearchListIndex = 0;
- // For DNSSEC questions, append search domains only if kDNSServiceFlagsValidateOptional is set
- if ((!(request->u.addrinfo.q6.ValidationRequired == DNSSEC_VALIDATION_SECURE)) && (!(request->u.addrinfo.q6.ValidationRequired == DNSSEC_VALIDATION_INSECURE))
- && ((hostnameLen == 0) || (hostname[hostnameLen - 1] != '.')) && (AlwaysAppendSearchDomains || CountLabels(&d) == 1))
- {
- request->u.addrinfo.q6.AppendSearchDomains = 1;
- request->u.addrinfo.q6.AppendLocalSearchDomains = 1;
- }
- else
- {
- request->u.addrinfo.q6.AppendSearchDomains = 0;
- request->u.addrinfo.q6.AppendLocalSearchDomains = 0;
- }
- request->u.addrinfo.q6.RetryWithSearchDomains = (ApplySearchDomainsFirst(&request->u.addrinfo.q6) ? 1 : 0);
- request->u.addrinfo.q6.QuestionCallback = queryrecord_result_callback;
- request->u.addrinfo.q6.QuestionContext = request;
- err = mDNS_StartQuery(&mDNSStorage, &request->u.addrinfo.q6);
- if (err != mStatus_NoError)
- {
- LogMsg("ERROR: mDNS_StartQuery: %d", (int)err);
- request->u.addrinfo.q6.QuestionContext = mDNSNULL;
- }
- #if APPLE_OSX_mDNSResponder
- err = SendAdditionalQuery(&request->u.addrinfo.q6, request, err);
- #endif // APPLE_OSX_mDNSResponder
- if (!err)
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER) && MDNSRESPONDER_SUPPORTS(APPLE, IPC_TLV)
+ if (request->msgptr && (request->hdr.ipc_flags & IPC_FLAGS_TRAILING_TLVS))
+ {
+ size_t len;
+ const mDNSu8 *const start = (const mDNSu8 *)request->msgptr;
+ const mDNSu8 *const end = (const mDNSu8 *)request->msgend;
+ const mDNSu8 *const data = ipc_tlv_get_resolver_config_plist_data(start, end, &len);
+ if (data)
{
- request->terminate = addrinfo_termination_callback;
- LogMcastQ(&request->u.addrinfo.q6, request, q_start);
- if (callExternalHelpers(InterfaceID, &d, flags))
- {
- LogDebug("handle_addrinfo_request: calling external_start_browsing_for_service() for AAAA record");
- external_start_browsing_for_service(InterfaceID, &d, kDNSServiceType_AAAA, flags);
- }
+ request->custom_service_id = Querier_RegisterCustomDNSServiceWithPListData(data, len);
}
+ params.require_privacy = ipc_tlv_get_require_privacy(start, end);
}
+#endif
+ request->flags = flags;
+ request->interfaceIndex = interfaceIndex;
- if (!err && (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv4))
- {
- request->u.addrinfo.q4.qtype = kDNSServiceType_A;
- request->u.addrinfo.q4.SearchListIndex = 0;
-
- // We append search domains only for queries that are a single label. If overriden using cmd line arg
- // "AlwaysAppendSearchDomains", then we do it for any query which is not fully qualified.
- // For DNSSEC questions, append search domains only if kDNSServiceFlagsValidateOptional is set.
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u] DNSServiceGetAddrInfo(%X, %d, %u, " PRI_S ") START PID[%d](" PUB_S ")",
+ request->request_id, request->flags, request->interfaceIndex, params.protocols, params.hostname, request->process_id,
+ request->pid_name);
- if ((!(request->u.addrinfo.q4.ValidationRequired == DNSSEC_VALIDATION_SECURE)) && (!(request->u.addrinfo.q4.ValidationRequired == DNSSEC_VALIDATION_INSECURE))
- && ((hostnameLen == 0) || (hostname[hostnameLen - 1] != '.')) && (AlwaysAppendSearchDomains || CountLabels(&d) == 1))
- {
- request->u.addrinfo.q4.AppendSearchDomains = 1;
- request->u.addrinfo.q4.AppendLocalSearchDomains = 1;
- }
- else
- {
- request->u.addrinfo.q4.AppendSearchDomains = 0;
- request->u.addrinfo.q4.AppendLocalSearchDomains = 0;
- }
- request->u.addrinfo.q4.RetryWithSearchDomains = (ApplySearchDomainsFirst(&request->u.addrinfo.q4) ? 1 : 0);
- request->u.addrinfo.q4.QuestionCallback = queryrecord_result_callback;
- request->u.addrinfo.q4.QuestionContext = request;
- err = mDNS_StartQuery(&mDNSStorage, &request->u.addrinfo.q4);
- if (err != mStatus_NoError)
- {
- LogMsg("ERROR: mDNS_StartQuery: %d", (int)err);
- request->u.addrinfo.q4.QuestionContext = mDNSNULL;
- if (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv6)
- {
- // If we started a query for IPv6, we need to cancel it
- mDNS_StopQuery(&mDNSStorage, &request->u.addrinfo.q6);
- request->u.addrinfo.q6.QuestionContext = mDNSNULL;
+ mDNSPlatformMemZero(&request->u.addrinfo, (mDNSu32)sizeof(request->u.addrinfo));
+ request->terminate = NULL;
- if (callExternalHelpers(InterfaceID, &d, flags))
- {
- LogInfo("addrinfo_termination_callback: calling external_stop_browsing_for_service() for AAAA record");
- external_stop_browsing_for_service(InterfaceID, &d, kDNSServiceType_AAAA, flags);
- }
- }
- }
- #if APPLE_OSX_mDNSResponder
- err = SendAdditionalQuery(&request->u.addrinfo.q4, request, err);
- #endif // APPLE_OSX_mDNSResponder
- if (!err)
- {
- request->terminate = addrinfo_termination_callback;
- LogMcastQ(&request->u.addrinfo.q4, request, q_start);
- if (callExternalHelpers(InterfaceID, &d, flags))
- {
- LogDebug("handle_addrinfo_request: calling external_start_browsing_for_service() for A record");
- external_start_browsing_for_service(InterfaceID, &d, kDNSServiceType_A, flags);
- }
- }
+#if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
+ if (os_feature_enabled(mDNSResponder, bonjour_privacy))
+ {
+ err = _handle_addrinfo_request_with_trust(request, &params);
+ }
+ else
+ {
+ err = _handle_addrinfo_request_start(request, &params);
}
+#else
+ err = _handle_addrinfo_request_start(request, &params);
+#endif
+exit:
return(err);
}
@@ -4580,14 +4562,13 @@ mDNSlocal mStatus handle_addrinfo_request(request_state *request)
mDNSlocal request_state *NewRequest(void)
{
+ request_state *request;
request_state **p = &all_requests;
- while (*p)
- p=&(*p)->next;
- *p = mallocL("request_state", sizeof(request_state));
- if (!*p)
- FatalError("ERROR: malloc");
- mDNSPlatformMemZero(*p, sizeof(request_state));
- return(*p);
+ request = (request_state *) callocL("request_state", sizeof(*request));
+ if (!request) FatalError("ERROR: calloc");
+ while (*p) p = &(*p)->next;
+ *p = request;
+ return(request);
}
// read_msg may be called any time when the transfer state (req->ts) is t_morecoming.
@@ -4595,7 +4576,12 @@ mDNSlocal request_state *NewRequest(void)
mDNSlocal void read_msg(request_state *req)
{
if (req->ts == t_terminated || req->ts == t_error)
- { LogMsg("%3d: ERROR: read_msg called with transfer state terminated or error", req->sd); req->ts = t_error; return; }
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[R%u] ERROR: read_msg called with transfer state terminated or error", req->request_id);
+ req->ts = t_error;
+ return;
+ }
if (req->ts == t_complete) // this must be death or something is wrong
{
@@ -4603,13 +4589,19 @@ mDNSlocal void read_msg(request_state *req)
int nread = udsSupportReadFD(req->sd, buf, 4, 0, req->platform_data);
if (!nread) { req->ts = t_terminated; return; }
if (nread < 0) goto rerror;
- LogMsg("%3d: ERROR: read data from a completed request", req->sd);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[R%u] ERROR: read data from a completed request", req->request_id);
req->ts = t_error;
return;
}
if (req->ts != t_morecoming)
- { LogMsg("%3d: ERROR: read_msg called with invalid transfer state (%d)", req->sd, req->ts); req->ts = t_error; return; }
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[R%u] ERROR: read_msg called with invalid transfer state (%d)", req->request_id, req->ts);
+ req->ts = t_error;
+ return;
+ }
if (req->hdr_bytes < sizeof(ipc_msg_hdr))
{
@@ -4619,25 +4611,39 @@ mDNSlocal void read_msg(request_state *req)
if (nread < 0) goto rerror;
req->hdr_bytes += nread;
if (req->hdr_bytes > sizeof(ipc_msg_hdr))
- { LogMsg("%3d: ERROR: read_msg - read too many header bytes", req->sd); req->ts = t_error; return; }
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[R%u] ERROR: read_msg - read too many header bytes", req->request_id);
+ req->ts = t_error;
+ return;
+ }
// only read data if header is complete
if (req->hdr_bytes == sizeof(ipc_msg_hdr))
{
ConvertHeaderBytes(&req->hdr);
if (req->hdr.version != VERSION)
- { LogMsg("%3d: ERROR: client version 0x%08X daemon version 0x%08X", req->sd, req->hdr.version, VERSION); req->ts = t_error; return; }
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[R%u] ERROR: client version 0x%08X daemon version 0x%08X", req->request_id, req->hdr.version, VERSION);
+ req->ts = t_error;
+ return;
+ }
// Largest conceivable single request is a DNSServiceRegisterRecord() or DNSServiceAddRecord()
// with 64kB of rdata. Adding 1009 byte for a maximal domain name, plus a safety margin
// for other overhead, this means any message above 70kB is definitely bogus.
if (req->hdr.datalen > 70000)
- { LogMsg("%3d: ERROR: read_msg: hdr.datalen %u (0x%X) > 70000", req->sd, req->hdr.datalen, req->hdr.datalen); req->ts = t_error; return; }
- req->msgbuf = mallocL("request_state msgbuf", req->hdr.datalen + MSG_PAD_BYTES);
- if (!req->msgbuf) { my_perror("ERROR: malloc"); req->ts = t_error; return; }
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[R%u] ERROR: read_msg: hdr.datalen %u (0x%X) > 70000", req->request_id, req->hdr.datalen, req->hdr.datalen);
+ req->ts = t_error;
+ return;
+ }
+ req->msgbuf = (char *) callocL("request_state msgbuf", req->hdr.datalen + MSG_PAD_BYTES);
+ if (!req->msgbuf) { my_perror("ERROR: calloc"); req->ts = t_error; return; }
req->msgptr = req->msgbuf;
req->msgend = req->msgbuf + req->hdr.datalen;
- mDNSPlatformMemZero(req->msgbuf, req->hdr.datalen + MSG_PAD_BYTES);
}
}
@@ -4648,7 +4654,7 @@ mDNSlocal void read_msg(request_state *req)
if (req->hdr_bytes == sizeof(ipc_msg_hdr) && req->data_bytes < req->hdr.datalen)
{
mDNSu32 nleft = req->hdr.datalen - req->data_bytes;
- int nread;
+ ssize_t nread;
#if !defined(_WIN32)
struct iovec vec = { req->msgbuf + req->data_bytes, nleft }; // Tell recvmsg where we want the bytes put
struct msghdr msg;
@@ -4669,12 +4675,19 @@ mDNSlocal void read_msg(request_state *req)
if (nread < 0) goto rerror;
req->data_bytes += nread;
if (req->data_bytes > req->hdr.datalen)
- { LogMsg("%3d: ERROR: read_msg - read too many data bytes", req->sd); req->ts = t_error; return; }
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[R%u] ERROR: read_msg - read too many data bytes", req->request_id);
+ req->ts = t_error;
+ return;
+ }
#if !defined(_WIN32)
cmsg = CMSG_FIRSTHDR(&msg);
#if DEBUG_64BIT_SCM_RIGHTS
- LogMsg("%3d: Expecting %d %d %d %d", req->sd, sizeof(cbuf), sizeof(cbuf), SOL_SOCKET, SCM_RIGHTS);
- LogMsg("%3d: Got %d %d %d %d", req->sd, msg.msg_controllen, cmsg ? cmsg->cmsg_len : -1, cmsg ? cmsg->cmsg_level : -1, cmsg ? cmsg->cmsg_type : -1);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%u] Expecting %d %d %d %d", req->request_id, sizeof(cbuf), sizeof(cbuf), SOL_SOCKET, SCM_RIGHTS);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%u] Got %d %d %d %d", req->request_id, msg.msg_controllen, cmsg ? cmsg->cmsg_len : -1, cmsg ? cmsg->cmsg_level : -1, cmsg ? cmsg->cmsg_type : -1);
#endif // DEBUG_64BIT_SCM_RIGHTS
if (cmsg && cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
{
@@ -4685,19 +4698,22 @@ mDNSlocal void read_msg(request_state *req)
if (req->hdr.op == send_bpf)
{
dnssd_sock_t x = *(dnssd_sock_t *)CMSG_DATA(cmsg);
- LogOperation("%3d: Got len %d, BPF %d", req->sd, cmsg->cmsg_len, x);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%u] Got len %d, BPF %d", req->request_id, cmsg->cmsg_len, x);
mDNSPlatformReceiveBPF_fd(x);
}
else
#endif // APPLE_OSX_mDNSResponder
req->errsd = *(dnssd_sock_t *)CMSG_DATA(cmsg);
#if DEBUG_64BIT_SCM_RIGHTS
- LogMsg("%3d: read req->errsd %d", req->sd, req->errsd);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%u] read req->errsd %d", req->request_id, req->errsd);
#endif // DEBUG_64BIT_SCM_RIGHTS
if (req->data_bytes < req->hdr.datalen)
{
- LogMsg("%3d: Client(PID [%d](%s)) sent result code socket %d via SCM_RIGHTS with req->data_bytes %d < req->hdr.datalen %d",
- req->sd, req->process_id, req->pid_name, req->errsd, req->data_bytes, req->hdr.datalen);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+ "[R%u] Client(PID [%d](" PUB_S ")) sent result code socket %d via SCM_RIGHTS with req->data_bytes %d < req->hdr.datalen %d",
+ req->request_id, req->process_id, req->pid_name, req->errsd, req->data_bytes, req->hdr.datalen);
req->ts = t_error;
return;
}
@@ -4732,7 +4748,12 @@ mDNSlocal void read_msg(request_state *req)
if (ctrl_path[0] == 0)
{
if (req->errsd == req->sd)
- { LogMsg("%3d: read_msg: ERROR failed to get errsd via SCM_RIGHTS", req->sd); req->ts = t_error; return; }
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[R%u] read_msg: ERROR failed to get errsd via SCM_RIGHTS", req->request_id);
+ req->ts = t_error;
+ return;
+ }
goto got_errfd;
}
#endif
@@ -4749,12 +4770,21 @@ mDNSlocal void read_msg(request_state *req)
{
#if !defined(USE_TCP_LOOPBACK)
struct stat sb;
- LogMsg("%3d: read_msg: Couldn't connect to error return path socket “%s” errno %d (%s)",
- req->sd, cliaddr.sun_path, dnssd_errno, dnssd_strerror(dnssd_errno));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[R%u] read_msg: Couldn't connect to error return path socket " PUB_S " errno %d (" PUB_S ")",
+ req->request_id, cliaddr.sun_path, dnssd_errno, dnssd_strerror(dnssd_errno));
if (stat(cliaddr.sun_path, &sb) < 0)
- LogMsg("%3d: read_msg: stat failed “%s” errno %d (%s)", req->sd, cliaddr.sun_path, dnssd_errno, dnssd_strerror(dnssd_errno));
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[R%u] read_msg: stat failed " PUB_S " errno %d (" PUB_S ")",
+ req->request_id, cliaddr.sun_path, dnssd_errno, dnssd_strerror(dnssd_errno));
+ }
else
- LogMsg("%3d: read_msg: file “%s” mode %o (octal) uid %d gid %d", req->sd, cliaddr.sun_path, sb.st_mode, sb.st_uid, sb.st_gid);
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[R%u] read_msg: file " PUB_S " mode %o (octal) uid %d gid %d",
+ req->request_id, cliaddr.sun_path, sb.st_mode, sb.st_uid, sb.st_gid);
+ }
#endif
req->ts = t_error;
return;
@@ -4763,15 +4793,16 @@ mDNSlocal void read_msg(request_state *req)
#if !defined(USE_TCP_LOOPBACK)
got_errfd:
#endif
- LogDebug("%3d: Result code socket %d created %08X %08X", req->sd, req->errsd, req->hdr.client_context.u32[1], req->hdr.client_context.u32[0]);
+
#if defined(_WIN32)
if (ioctlsocket(req->errsd, FIONBIO, &opt) != 0)
#else
if (fcntl(req->errsd, F_SETFL, fcntl(req->errsd, F_GETFL, 0) | O_NONBLOCK) != 0)
#endif
{
- LogMsg("%3d: ERROR: could not set control socket to non-blocking mode errno %d (%s)",
- req->sd, dnssd_errno, dnssd_strerror(dnssd_errno));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[R%u] ERROR: could not set control socket to non-blocking mode errno %d (" PUB_S ")",
+ req->request_id, dnssd_errno, dnssd_strerror(dnssd_errno));
req->ts = t_error;
return;
}
@@ -4784,24 +4815,30 @@ got_errfd:
rerror:
if (dnssd_errno == dnssd_EWOULDBLOCK || dnssd_errno == dnssd_EINTR) return;
- LogMsg("%3d: ERROR: read_msg errno %d (%s)", req->sd, dnssd_errno, dnssd_strerror(dnssd_errno));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[R%u] ERROR: read_msg errno %d (" PUB_S ")", req->request_id, dnssd_errno, dnssd_strerror(dnssd_errno));
req->ts = t_error;
}
mDNSlocal mStatus handle_client_request(request_state *req)
{
mStatus err = mStatus_NoError;
+#if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
+ SetupAuditTokenForRequest(req);
+#endif
switch(req->hdr.op)
{
// These are all operations that have their own first-class request_state object
case connection_request:
- LogOperation("%3d: DNSServiceCreateConnection START PID[%d](%s)",
- req->sd, req->process_id, req->pid_name);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceCreateConnection START PID[%d](" PUB_S ")",
+ req->request_id, req->process_id, req->pid_name);
req->terminate = connection_termination;
break;
case connection_delegate_request:
- LogOperation("%3d: DNSServiceCreateDelegateConnection START PID[%d](%s)",
- req->sd, req->process_id, req->pid_name);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceCreateDelegateConnection START PID[%d](" PRI_S ")",
+ req->request_id, req->process_id, req->pid_name);
req->terminate = connection_termination;
handle_connection_delegate_request(req);
break;
@@ -4813,7 +4850,6 @@ mDNSlocal mStatus handle_client_request(request_state *req)
case reconfirm_record_request: err = handle_reconfirm_request (req); break;
case setdomain_request: err = handle_setdomain_request (req); break;
case getproperty_request: handle_getproperty_request (req); break;
- case getpid_request: handle_getpid_request (req); break;
case port_mapping_request: err = handle_port_mapping_request(req); break;
case addrinfo_request: err = handle_addrinfo_request (req); break;
case send_bpf: /* Do nothing for send_bpf */ break;
@@ -4840,13 +4876,12 @@ mDNSlocal mStatus handle_client_request(request_state *req)
// The lightweight operations are the ones that don't need a dedicated request_state structure allocated for them
#define LightweightOp(X) (RecordOrientedOp(X) || (X) == cancel_request)
-mDNSlocal void request_callback(int fd, short filter, void *info)
+mDNSlocal void request_callback(int fd, void *info)
{
mStatus err = 0;
request_state *req = info;
mDNSs32 min_size = sizeof(DNSServiceFlags);
(void)fd; // Unused
- (void)filter; // Unused
for (;;)
{
@@ -4881,7 +4916,6 @@ mDNSlocal void request_callback(int fd, short filter, void *info)
case reconfirm_record_request: min_size += sizeof(mDNSu32) + 1 /* name */ + 6 /* type, class, rdlen */; break;
case setdomain_request: min_size += 1 /* domain */; break;
case getproperty_request: min_size = 2; break;
- case getpid_request: min_size = 2; break;
case port_mapping_request: min_size += sizeof(mDNSu32) + 4 /* udp/tcp */ + 4 /* int/ext port */ + 4 /* ttl */; break;
case addrinfo_request: min_size += sizeof(mDNSu32) + 4 /* v4/v6 */ + 1 /* hostname */; break;
case send_bpf: // Same as cancel_request below
@@ -4919,6 +4953,10 @@ mDNSlocal void request_callback(int fd, short filter, void *info)
newreq->msgbuf = req->msgbuf;
newreq->msgptr = req->msgptr;
newreq->msgend = req->msgend;
+ newreq->request_id = GetNewRequestID();
+#if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
+ newreq->audit_token = req->audit_token;
+#endif
// if the parent request is a delegate connection, copy the
// relevant bits
if (req->validUUID)
@@ -4962,8 +5000,6 @@ mDNSlocal void request_callback(int fd, short filter, void *info)
send_all(req->errsd, (const char *)&err_netorder, sizeof(err_netorder));
if (req->errsd != req->sd)
{
- LogDebug("%3d: Result code socket %d closed %08X %08X (%d)",
- req->sd, req->errsd, req->hdr.client_context.u32[1], req->hdr.client_context.u32[0], err);
dnssd_close(req->errsd);
req->errsd = req->sd;
// Also need to reset the parent's errsd, if this is a subordinate operation
@@ -4982,7 +5018,7 @@ mDNSlocal void request_callback(int fd, short filter, void *info)
}
}
-mDNSlocal void connect_callback(int fd, short filter, void *info)
+mDNSlocal void connect_callback(int fd, void *info)
{
dnssd_sockaddr_t cliaddr;
dnssd_socklen_t len = (dnssd_socklen_t) sizeof(cliaddr);
@@ -4991,7 +5027,6 @@ mDNSlocal void connect_callback(int fd, short filter, void *info)
unsigned long optval = 1;
#endif
- (void)filter; // Unused
(void)info; // Unused
if (!dnssd_SocketValid(sd))
@@ -5023,6 +5058,7 @@ mDNSlocal void connect_callback(int fd, short filter, void *info)
request->ts = t_morecoming;
request->sd = sd;
request->errsd = sd;
+ request->request_id = GetNewRequestID();
set_peer_pid(request);
#if APPLE_OSX_mDNSResponder
struct xucred x;
@@ -5031,7 +5067,6 @@ mDNSlocal void connect_callback(int fd, short filter, void *info)
request->uid = x.cr_uid; // save the effective userid of the client
else
my_perror("ERROR: getsockopt, LOCAL_PEERCRED");
-
debugf("LOCAL_PEERCRED %d %u %u %d", xucredlen, x.cr_version, x.cr_uid, x.cr_ngroups);
#endif // APPLE_OSX_mDNSResponder
LogDebug("%3d: connect_callback: Adding FD for uid %u", request->sd, request->uid);
@@ -5081,27 +5116,32 @@ mDNSlocal mDNSBool uds_socket_setup(dnssd_sock_t skt)
return mDNStrue;
}
-mDNSexport int udsserver_init(dnssd_sock_t skts[], mDNSu32 count)
+#if MDNS_MALLOC_DEBUGGING
+mDNSlocal void udsserver_validatelists(void *context);
+#endif
+
+mDNSexport int udsserver_init(dnssd_sock_t skts[], const size_t count)
{
dnssd_sockaddr_t laddr;
int ret;
- mDNSu32 i = 0;
- LogInfo("udsserver_init: %d %d", _DNS_SD_H, mDNSStorage.mDNS_plat);
-
- // If a particular platform wants to opt out of having a PID file, define PID_FILE to be ""
- if (PID_FILE[0])
+#ifndef NO_PID_FILE
+ FILE *fp = fopen(PID_FILE, "w");
+ if (fp != NULL)
{
- FILE *fp = fopen(PID_FILE, "w");
- if (fp != NULL)
- {
- fprintf(fp, "%d\n", (int)getpid());
- fclose(fp);
- }
+ fprintf(fp, "%d\n", getpid());
+ fclose(fp);
}
+#endif
+
+#if MDNS_MALLOC_DEBUGGING
+ static mDNSListValidator validator;
+ mDNSPlatformAddListValidator(&validator, udsserver_validatelists, "udsserver_validatelists", NULL);
+#endif
if (skts)
{
+ size_t i;
for (i = 0; i < count; i++)
if (dnssd_SocketValid(skts[i]) && !uds_socket_setup(skts[i]))
goto error;
@@ -5229,21 +5269,100 @@ mDNSexport int udsserver_exit(void)
#endif
}
- if (PID_FILE[0]) unlink(PID_FILE);
+#ifndef NO_PID_FILE
+ unlink(PID_FILE);
+#endif
return 0;
}
-mDNSlocal void LogClientInfo(request_state *req)
+mDNSlocal void LogClientInfoToFD(int fd, request_state *req)
{
- char prefix[16];
- if (req->primary)
- mDNS_snprintf(prefix, sizeof(prefix), " -> ");
+ char reqIDStr[14];
+ char prefix[18];
+
+ mDNS_snprintf(reqIDStr, sizeof(reqIDStr), "[R%u]", req->request_id);
+
+ mDNS_snprintf(prefix, sizeof(prefix), "%-6s %2s", reqIDStr, req->primary ? "->" : "");
+
+ if (!req->terminate)
+ LogToFD(fd, "%s No operation yet on this socket", prefix);
+ else if (req->terminate == connection_termination)
+ {
+ int num_records = 0, num_ops = 0;
+ const registered_record_entry *p;
+ request_state *r;
+ for (p = req->u.reg_recs; p; p=p->next) num_records++;
+ for (r = req->next; r; r=r->next) if (r->primary == req) num_ops++;
+ LogToFD(fd, "%s DNSServiceCreateConnection: %d registered record%s, %d kDNSServiceFlagsShareConnection operation%s PID[%d](%s)",
+ prefix, num_records, num_records != 1 ? "s" : "", num_ops, num_ops != 1 ? "s" : "",
+ req->process_id, req->pid_name);
+ for (p = req->u.reg_recs; p; p=p->next)
+ LogToFD(fd, " -> DNSServiceRegisterRecord 0x%08X %2d %3d %s PID[%d](%s)",
+ req->flags, req->interfaceIndex, p->key, ARDisplayString(&mDNSStorage, p->rr), req->process_id, req->pid_name);
+ for (r = req->next; r; r=r->next) if (r->primary == req) LogClientInfoToFD(fd, r);
+ }
+ else if (req->terminate == regservice_termination_callback)
+ {
+ service_instance *ptr;
+ for (ptr = req->u.servicereg.instances; ptr; ptr = ptr->next)
+ LogToFD(fd, "%-9s DNSServiceRegister 0x%08X %2d %##s %u/%u PID[%d](%s)",
+ (ptr == req->u.servicereg.instances) ? prefix : "", req->flags, req->interfaceIndex, ptr->srs.RR_SRV.resrec.name->c,
+ mDNSVal16(req->u.servicereg.port),
+ SRS_PORT(&ptr->srs), req->process_id, req->pid_name);
+ }
+ else if (req->terminate == browse_termination_callback)
+ {
+ browser_t *blist;
+ for (blist = req->u.browser.browsers; blist; blist = blist->next)
+ LogToFD(fd, "%-9s DNSServiceBrowse 0x%08X %2d %##s PID[%d](%s)",
+ (blist == req->u.browser.browsers) ? prefix : "", req->flags, req->interfaceIndex, blist->q.qname.c,
+ req->process_id, req->pid_name);
+ }
+ else if (req->terminate == resolve_termination_callback)
+ LogToFD(fd, "%s DNSServiceResolve 0x%08X %2d %##s PID[%d](%s)",
+ prefix, req->flags, req->interfaceIndex, req->u.resolve.qsrv.qname.c, req->process_id, req->pid_name);
+ else if (req->terminate == queryrecord_termination_callback)
+ LogToFD(fd, "%s DNSServiceQueryRecord 0x%08X %2d %##s (%s) PID[%d](%s)",
+ prefix, req->flags, req->interfaceIndex, QueryRecordClientRequestGetQName(&req->u.queryrecord), DNSTypeName(QueryRecordClientRequestGetType(&req->u.queryrecord)), req->process_id, req->pid_name);
+ else if (req->terminate == enum_termination_callback)
+ LogToFD(fd, "%s DNSServiceEnumerateDomains 0x%08X %2d %##s PID[%d](%s)",
+ prefix, req->flags, req->interfaceIndex, req->u.enumeration.q_all.qname.c, req->process_id, req->pid_name);
+ else if (req->terminate == port_mapping_termination_callback)
+ LogToFD(fd, "%s DNSServiceNATPortMapping 0x%08X %2d %s%s Int %5d Req %5d Ext %.4a:%5d Req TTL %5d Granted TTL %5d PID[%d](%s)",
+ prefix,
+ req->flags,
+ req->interfaceIndex,
+ req->u.pm.NATinfo.Protocol & NATOp_MapTCP ? "TCP" : " ",
+ req->u.pm.NATinfo.Protocol & NATOp_MapUDP ? "UDP" : " ",
+ mDNSVal16(req->u.pm.NATinfo.IntPort),
+ mDNSVal16(req->u.pm.ReqExt),
+ &req->u.pm.NATinfo.ExternalAddress,
+ mDNSVal16(req->u.pm.NATinfo.ExternalPort),
+ req->u.pm.NATinfo.NATLease,
+ req->u.pm.NATinfo.Lifetime,
+ req->process_id, req->pid_name);
+ else if (req->terminate == addrinfo_termination_callback)
+ LogToFD(fd, "%s DNSServiceGetAddrInfo 0x%08X %2d %s%s %##s PID[%d](%s)",
+ prefix, req->flags, req->interfaceIndex,
+ req->u.addrinfo.protocols & kDNSServiceProtocol_IPv4 ? "v4" : " ",
+ req->u.addrinfo.protocols & kDNSServiceProtocol_IPv6 ? "v6" : " ",
+ GetAddrInfoClientRequestGetQName(&req->u.addrinfo), req->process_id, req->pid_name);
else
- mDNS_snprintf(prefix, sizeof(prefix), "%3d:", req->sd);
+ LogToFD(fd, "%s Unrecognized operation %p", prefix, req->terminate);
+}
+
+mDNSlocal void LogClientInfo(request_state *req)
+{
+ char reqIDStr[14];
+ char prefix[18];
+
+ mDNS_snprintf(reqIDStr, sizeof(reqIDStr), "[R%u]", req->request_id);
+
+ mDNS_snprintf(prefix, sizeof(prefix), "%-6s %2s", reqIDStr, req->primary ? "->" : "");
if (!req->terminate)
- LogMsgNoIdent("%s No operation yet on this socket", prefix);
+ LogMsgNoIdent("%s No operation yet on this socket", prefix);
else if (req->terminate == connection_termination)
{
int num_records = 0, num_ops = 0;
@@ -5252,63 +5371,61 @@ mDNSlocal void LogClientInfo(request_state *req)
for (p = req->u.reg_recs; p; p=p->next) num_records++;
for (r = req->next; r; r=r->next) if (r->primary == req) num_ops++;
LogMsgNoIdent("%s DNSServiceCreateConnection: %d registered record%s, %d kDNSServiceFlagsShareConnection operation%s PID[%d](%s)",
- prefix, num_records, num_records != 1 ? "s" : "", num_ops, num_ops != 1 ? "s" : "",
- req->process_id, req->pid_name);
+ prefix, num_records, num_records != 1 ? "s" : "", num_ops, num_ops != 1 ? "s" : "",
+ req->process_id, req->pid_name);
for (p = req->u.reg_recs; p; p=p->next)
- LogMsgNoIdent(" -> DNSServiceRegisterRecord 0x%08X %2d %3d %s PID[%d](%s)",
- req->flags, req->interfaceIndex, p->key, ARDisplayString(&mDNSStorage, p->rr), req->process_id, req->pid_name);
+ LogMsgNoIdent(" -> DNSServiceRegisterRecord 0x%08X %2d %3d %s PID[%d](%s)",
+ req->flags, req->interfaceIndex, p->key, ARDisplayString(&mDNSStorage, p->rr), req->process_id, req->pid_name);
for (r = req->next; r; r=r->next) if (r->primary == req) LogClientInfo(r);
}
else if (req->terminate == regservice_termination_callback)
{
service_instance *ptr;
- char anonstr[256];
for (ptr = req->u.servicereg.instances; ptr; ptr = ptr->next)
- LogMsgNoIdent("%s DNSServiceRegister 0x%08X %2d %##s%s %u/%u PID[%d](%s)",
- (ptr == req->u.servicereg.instances) ? prefix : " ", req->flags, req->interfaceIndex, ptr->srs.RR_SRV.resrec.name->c,
- AnonDataToString(ptr->srs.AnonData, 0, anonstr, sizeof(anonstr)), mDNSVal16(req->u.servicereg.port),
- SRS_PORT(&ptr->srs), req->process_id, req->pid_name);
+ LogMsgNoIdent("%-9s DNSServiceRegister 0x%08X %2d %##s %u/%u PID[%d](%s)",
+ (ptr == req->u.servicereg.instances) ? prefix : "", req->flags, req->interfaceIndex, ptr->srs.RR_SRV.resrec.name->c,
+ mDNSVal16(req->u.servicereg.port),
+ SRS_PORT(&ptr->srs), req->process_id, req->pid_name);
}
else if (req->terminate == browse_termination_callback)
{
browser_t *blist;
- char anonstr[256];
for (blist = req->u.browser.browsers; blist; blist = blist->next)
- LogMsgNoIdent("%s DNSServiceBrowse 0x%08X %2d %##s%s PID[%d](%s)",
- (blist == req->u.browser.browsers) ? prefix : " ", req->flags, req->interfaceIndex, blist->q.qname.c,
- AnonDataToString(req->u.browser.AnonData, 0, anonstr, sizeof(anonstr)), req->process_id, req->pid_name);
+ LogMsgNoIdent("%-9s DNSServiceBrowse 0x%08X %2d %##s PID[%d](%s)",
+ (blist == req->u.browser.browsers) ? prefix : "", req->flags, req->interfaceIndex, blist->q.qname.c,
+ req->process_id, req->pid_name);
}
else if (req->terminate == resolve_termination_callback)
- LogMsgNoIdent("%s DNSServiceResolve 0x%08X %2d %##s PID[%d](%s)",
- prefix, req->flags, req->interfaceIndex, req->u.resolve.qsrv.qname.c, req->process_id, req->pid_name);
+ LogMsgNoIdent("%s DNSServiceResolve 0x%08X %2d %##s PID[%d](%s)",
+ prefix, req->flags, req->interfaceIndex, req->u.resolve.qsrv.qname.c, req->process_id, req->pid_name);
else if (req->terminate == queryrecord_termination_callback)
- LogMsgNoIdent("%s DNSServiceQueryRecord 0x%08X %2d %##s (%s) PID[%d](%s)",
- prefix, req->flags, req->interfaceIndex, req->u.queryrecord.q.qname.c, DNSTypeName(req->u.queryrecord.q.qtype), req->process_id, req->pid_name);
+ LogMsgNoIdent("%s DNSServiceQueryRecord 0x%08X %2d %##s (%s) PID[%d](%s)",
+ prefix, req->flags, req->interfaceIndex, QueryRecordClientRequestGetQName(&req->u.queryrecord), DNSTypeName(QueryRecordClientRequestGetType(&req->u.queryrecord)), req->process_id, req->pid_name);
else if (req->terminate == enum_termination_callback)
- LogMsgNoIdent("%s DNSServiceEnumerateDomains 0x%08X %2d %##s PID[%d](%s)",
- prefix, req->flags, req->interfaceIndex, req->u.enumeration.q_all.qname.c, req->process_id, req->pid_name);
+ LogMsgNoIdent("%s DNSServiceEnumerateDomains 0x%08X %2d %##s PID[%d](%s)",
+ prefix, req->flags, req->interfaceIndex, req->u.enumeration.q_all.qname.c, req->process_id, req->pid_name);
else if (req->terminate == port_mapping_termination_callback)
- LogMsgNoIdent("%s DNSServiceNATPortMapping 0x%08X %2d %s%s Int %5d Req %5d Ext %.4a:%5d Req TTL %5d Granted TTL %5d PID[%d](%s)",
- prefix,
- req->flags,
- req->interfaceIndex,
- req->u.pm.NATinfo.Protocol & NATOp_MapTCP ? "TCP" : " ",
- req->u.pm.NATinfo.Protocol & NATOp_MapUDP ? "UDP" : " ",
- mDNSVal16(req->u.pm.NATinfo.IntPort),
- mDNSVal16(req->u.pm.ReqExt),
- &req->u.pm.NATinfo.ExternalAddress,
- mDNSVal16(req->u.pm.NATinfo.ExternalPort),
- req->u.pm.NATinfo.NATLease,
- req->u.pm.NATinfo.Lifetime,
- req->process_id, req->pid_name);
+ LogMsgNoIdent("%s DNSServiceNATPortMapping 0x%08X %2d %s%s Int %5d Req %5d Ext %.4a:%5d Req TTL %5d Granted TTL %5d PID[%d](%s)",
+ prefix,
+ req->flags,
+ req->interfaceIndex,
+ req->u.pm.NATinfo.Protocol & NATOp_MapTCP ? "TCP" : " ",
+ req->u.pm.NATinfo.Protocol & NATOp_MapUDP ? "UDP" : " ",
+ mDNSVal16(req->u.pm.NATinfo.IntPort),
+ mDNSVal16(req->u.pm.ReqExt),
+ &req->u.pm.NATinfo.ExternalAddress,
+ mDNSVal16(req->u.pm.NATinfo.ExternalPort),
+ req->u.pm.NATinfo.NATLease,
+ req->u.pm.NATinfo.Lifetime,
+ req->process_id, req->pid_name);
else if (req->terminate == addrinfo_termination_callback)
- LogMsgNoIdent("%s DNSServiceGetAddrInfo 0x%08X %2d %s%s %##s PID[%d](%s)",
- prefix, req->flags, req->interfaceIndex,
- req->u.addrinfo.protocol & kDNSServiceProtocol_IPv4 ? "v4" : " ",
- req->u.addrinfo.protocol & kDNSServiceProtocol_IPv6 ? "v6" : " ",
- req->u.addrinfo.q4.qname.c, req->process_id, req->pid_name);
+ LogMsgNoIdent("%s DNSServiceGetAddrInfo 0x%08X %2d %s%s %##s PID[%d](%s)",
+ prefix, req->flags, req->interfaceIndex,
+ req->u.addrinfo.protocols & kDNSServiceProtocol_IPv4 ? "v4" : " ",
+ req->u.addrinfo.protocols & kDNSServiceProtocol_IPv6 ? "v6" : " ",
+ GetAddrInfoClientRequestGetQName(&req->u.addrinfo), req->process_id, req->pid_name);
else
- LogMsgNoIdent("%s Unrecognized operation %p", prefix, req->terminate);
+ LogMsgNoIdent("%s Unrecognized operation %p", prefix, req->terminate);
}
mDNSlocal void GetMcastClients(request_state *req)
@@ -5357,12 +5474,12 @@ mDNSlocal void GetMcastClients(request_state *req)
}
else if (req->terminate == queryrecord_termination_callback)
{
- if ((mDNSOpaque16IsZero(req->u.queryrecord.q.TargetQID)) && (req->u.queryrecord.q.ThisQInterval > 0))
+ if (QueryRecordClientRequestIsMulticast(&req->u.queryrecord))
n_mquests++;
}
else if (req->terminate == addrinfo_termination_callback)
{
- if ((mDNSOpaque16IsZero(req->u.addrinfo.q4.TargetQID)) && (req->u.addrinfo.q4.ThisQInterval > 0))
+ if (GetAddrInfoClientRequestIsMulticast(&req->u.addrinfo))
n_mquests++;
}
else
@@ -5424,23 +5541,24 @@ mDNSlocal void LogMcastClientInfo(request_state *req)
}
else if (req->terminate == queryrecord_termination_callback)
{
- if ((mDNSOpaque16IsZero(req->u.queryrecord.q.TargetQID)) && (req->u.queryrecord.q.ThisQInterval > 0))
- LogMcastNoIdent("Q: DNSServiceQueryRecord %##s %s PID[%d](%s)", req->u.queryrecord.q.qname.c, DNSTypeName(req->u.queryrecord.q.qtype),
+ if (QueryRecordClientRequestIsMulticast(&req->u.queryrecord))
+ {
+ LogMcastNoIdent("Q: DNSServiceQueryRecord %##s %s PID[%d](%s)",
+ QueryRecordClientRequestGetQName(&req->u.queryrecord),
+ DNSTypeName(QueryRecordClientRequestGetType(&req->u.queryrecord)),
req->process_id, req->pid_name, i_mcount++);
+ }
}
else if (req->terminate == addrinfo_termination_callback)
{
- if ((mDNSOpaque16IsZero(req->u.addrinfo.q4.TargetQID)) && (req->u.addrinfo.q4.ThisQInterval > 0))
+ if (GetAddrInfoClientRequestIsMulticast(&req->u.addrinfo))
+ {
LogMcastNoIdent("Q: DNSServiceGetAddrInfo %s%s %##s PID[%d](%s)",
- req->u.addrinfo.protocol & kDNSServiceProtocol_IPv4 ? "v4" : " ",
- req->u.addrinfo.protocol & kDNSServiceProtocol_IPv6 ? "v6" : " ",
- req->u.addrinfo.q4.qname.c, req->process_id, req->pid_name, i_mcount++);
- }
- else
- {
- return;
+ req->u.addrinfo.protocols & kDNSServiceProtocol_IPv4 ? "v4" : " ",
+ req->u.addrinfo.protocols & kDNSServiceProtocol_IPv6 ? "v6" : " ",
+ GetAddrInfoClientRequestGetQName(&req->u.addrinfo), req->process_id, req->pid_name, i_mcount++);
+ }
}
-
}
mDNSlocal char *RecordTypeName(mDNSu8 rtype)
@@ -5458,7 +5576,7 @@ mDNSlocal char *RecordTypeName(mDNSu8 rtype)
}
}
-mDNSlocal int LogEtcHosts(mDNS *const m)
+mDNSlocal int LogEtcHostsToFD(int fd, mDNS *const m)
{
mDNSBool showheader = mDNStrue;
const AuthRecord *ar;
@@ -5475,29 +5593,29 @@ mDNSlocal int LogEtcHosts(mDNS *const m)
for (ar = ag->members; ar; ar = ar->next)
{
if (ar->RecordCallback != FreeEtcHosts) continue;
- if (showheader) { showheader = mDNSfalse; LogMsgNoIdent(" State Interface"); }
+ if (showheader) { showheader = mDNSfalse; LogToFD(fd, " State Interface"); }
// Print a maximum of 50 records
if (count++ >= 50) { truncated = mDNStrue; continue; }
if (ar->ARType == AuthRecordLocalOnly)
{
if (ar->resrec.InterfaceID == mDNSInterface_LocalOnly)
- LogMsgNoIdent(" %s LO %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar));
+ LogToFD(fd, " %s LO %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar));
else
{
mDNSu32 scopeid = (mDNSu32)(uintptr_t)ar->resrec.InterfaceID;
- LogMsgNoIdent(" %s %u %s", RecordTypeName(ar->resrec.RecordType), scopeid, ARDisplayString(m, ar));
+ LogToFD(fd, " %s %u %s", RecordTypeName(ar->resrec.RecordType), scopeid, ARDisplayString(m, ar));
}
}
}
}
- if (showheader) LogMsgNoIdent("<None>");
- else if (truncated) LogMsgNoIdent("<Truncated: to 50 records, Total records %d, Total Auth Groups %d, Auth Slots %d>", count, m->rrauth.rrauth_totalused, authslot);
+ if (showheader) LogToFD(fd, "<None>");
+ else if (truncated) LogToFD(fd, "<Truncated: to 50 records, Total records %d, Total Auth Groups %d, Auth Slots %d>", count, m->rrauth.rrauth_totalused, authslot);
return count;
}
-mDNSlocal void LogLocalOnlyAuthRecords(mDNS *const m)
+mDNSlocal void LogLocalOnlyAuthRecordsToFD(int fd, mDNS *const m)
{
mDNSBool showheader = mDNStrue;
const AuthRecord *ar;
@@ -5510,62 +5628,52 @@ mDNSlocal void LogLocalOnlyAuthRecords(mDNS *const m)
for (ar = ag->members; ar; ar = ar->next)
{
if (ar->RecordCallback == FreeEtcHosts) continue;
- if (showheader) { showheader = mDNSfalse; LogMsgNoIdent(" State Interface"); }
+ if (showheader) { showheader = mDNSfalse; LogToFD(fd, " State Interface"); }
// Print a maximum of 400 records
if (ar->ARType == AuthRecordLocalOnly)
- LogMsgNoIdent(" %s LO %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar));
+ LogToFD(fd, " %s LO %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar));
else if (ar->ARType == AuthRecordP2P)
{
if (ar->resrec.InterfaceID == mDNSInterface_BLE)
- LogMsgNoIdent(" %s BLE %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar));
+ LogToFD(fd, " %s BLE %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar));
else
- LogMsgNoIdent(" %s PP %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar));
+ LogToFD(fd, " %s PP %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar));
}
}
}
- if (showheader) LogMsgNoIdent("<None>");
+ if (showheader) LogToFD(fd, "<None>");
}
-mDNSlocal char *AnonInfoToString(AnonymousInfo *ai, char *anonstr, int anstrlen)
+mDNSlocal void LogOneAuthRecordToFD(int fd, const AuthRecord *ar, mDNSs32 now, const char *ifname)
{
- anonstr[0] = 0;
- if (ai && ai->AnonData)
- {
- return (AnonDataToString(ai->AnonData, ai->AnonDataLen, anonstr, anstrlen));
- }
- return anonstr;
-}
-
-mDNSlocal void LogOneAuthRecord(const AuthRecord *ar, mDNSs32 now, const char *const ifname)
-{
- char anstr[256];
if (AuthRecord_uDNS(ar))
{
- LogMsgNoIdent("%7d %7d %7d %-7s %4d %s %s",
- ar->ThisAPInterval / mDNSPlatformOneSecond,
- (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond,
- ar->expire ? (ar->expire - now) / mDNSPlatformOneSecond : 0,
- "-U-",
- ar->state,
- ar->AllowRemoteQuery ? "☠" : " ",
- ARDisplayString(&mDNSStorage, ar));
+ LogToFD(fd, "%7d %7d %7d %-7s %4d %s %s",
+ ar->ThisAPInterval / mDNSPlatformOneSecond,
+ (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond,
+ ar->expire ? (ar->expire - now) / mDNSPlatformOneSecond : 0,
+ "-U-",
+ ar->state,
+ ar->AllowRemoteQuery ? "☠" : " ",
+ ARDisplayString(&mDNSStorage, ar));
}
else
{
- LogMsgNoIdent("%7d %7d %7d %-7s 0x%02X %s %s%s",
- ar->ThisAPInterval / mDNSPlatformOneSecond,
- ar->AnnounceCount ? (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond : 0,
- ar->TimeExpire ? (ar->TimeExpire - now) / mDNSPlatformOneSecond : 0,
- ifname ? ifname : "ALL",
- ar->resrec.RecordType,
- ar->AllowRemoteQuery ? "☠" : " ",
- ARDisplayString(&mDNSStorage, ar), AnonInfoToString(ar->resrec.AnonInfo, anstr, sizeof(anstr)));
+ LogToFD(fd, "%7d %7d %7d %-7s 0x%02X %s %s",
+ ar->ThisAPInterval / mDNSPlatformOneSecond,
+ ar->AnnounceCount ? (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond : 0,
+ ar->TimeExpire ? (ar->TimeExpire - now) / mDNSPlatformOneSecond : 0,
+ ifname ? ifname : "ALL",
+ ar->resrec.RecordType,
+ ar->AllowRemoteQuery ? "☠" : " ",
+ ARDisplayString(&mDNSStorage, ar));
}
}
-mDNSlocal void LogAuthRecords(const mDNSs32 now, AuthRecord *ResourceRecords, int *proxy)
+mDNSlocal void LogAuthRecordsToFD(int fd,
+ const mDNSs32 now, AuthRecord *ResourceRecords, int *proxy)
{
mDNSBool showheader = mDNStrue;
const AuthRecord *ar;
@@ -5575,169 +5683,102 @@ mDNSlocal void LogAuthRecords(const mDNSs32 now, AuthRecord *ResourceRecords, in
const char *const ifname = InterfaceNameForID(&mDNSStorage, ar->resrec.InterfaceID);
if ((ar->WakeUp.HMAC.l[0] != 0) == (proxy != mDNSNULL))
{
- if (showheader) { showheader = mDNSfalse; LogMsgNoIdent(" Int Next Expire if State"); }
+ if (showheader) { showheader = mDNSfalse; LogToFD(fd, " Int Next Expire if State"); }
if (proxy) (*proxy)++;
if (!mDNSPlatformMemSame(&owner, &ar->WakeUp, sizeof(owner)))
{
owner = ar->WakeUp;
if (owner.password.l[0])
- LogMsgNoIdent("Proxying for H-MAC %.6a I-MAC %.6a Password %.6a seq %d", &owner.HMAC, &owner.IMAC, &owner.password, owner.seq);
+ LogToFD(fd, "Proxying for H-MAC %.6a I-MAC %.6a Password %.6a seq %d", &owner.HMAC, &owner.IMAC, &owner.password, owner.seq);
else if (!mDNSSameEthAddress(&owner.HMAC, &owner.IMAC))
- LogMsgNoIdent("Proxying for H-MAC %.6a I-MAC %.6a seq %d", &owner.HMAC, &owner.IMAC, owner.seq);
+ LogToFD(fd, "Proxying for H-MAC %.6a I-MAC %.6a seq %d", &owner.HMAC, &owner.IMAC, owner.seq);
else
- LogMsgNoIdent("Proxying for %.6a seq %d", &owner.HMAC, owner.seq);
+ LogToFD(fd, "Proxying for %.6a seq %d", &owner.HMAC, owner.seq);
}
if (AuthRecord_uDNS(ar))
{
- LogOneAuthRecord(ar, now, ifname);
+ LogOneAuthRecordToFD(fd, ar, now, ifname);
}
else if (ar->ARType == AuthRecordLocalOnly)
{
- LogMsgNoIdent(" LO %s", ARDisplayString(&mDNSStorage, ar));
+ LogToFD(fd, " LO %s", ARDisplayString(&mDNSStorage, ar));
}
else if (ar->ARType == AuthRecordP2P)
{
if (ar->resrec.InterfaceID == mDNSInterface_BLE)
- LogMsgNoIdent(" BLE %s", ARDisplayString(&mDNSStorage, ar));
+ LogToFD(fd, " BLE %s", ARDisplayString(&mDNSStorage, ar));
else
- LogMsgNoIdent(" PP %s", ARDisplayString(&mDNSStorage, ar));
+ LogToFD(fd, " PP %s", ARDisplayString(&mDNSStorage, ar));
}
else
{
- LogOneAuthRecord(ar, now, ifname);
- if (ar->resrec.AnonInfo)
- {
- ResourceRecord *nsec3 = ar->resrec.AnonInfo->nsec3RR;
- // We just print the values from the AuthRecord to keep it nicely aligned though
- // all we want here is the nsec3 information.
- LogMsgNoIdent("%7d %7d %7d %7s %s",
- ar->ThisAPInterval / mDNSPlatformOneSecond,
- ar->AnnounceCount ? (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond : 0,
- ar->TimeExpire ? (ar->TimeExpire - now) / mDNSPlatformOneSecond : 0,
- ifname ? ifname : "ALL",
- RRDisplayString(&mDNSStorage, nsec3));
- }
+ LogOneAuthRecordToFD(fd, ar, now, ifname);
}
}
}
- if (showheader) LogMsgNoIdent("<None>");
+ if (showheader) LogToFD(fd, "<None>");
}
-mDNSlocal void PrintOneCacheRecord(const CacheRecord *cr, mDNSu32 slot, const mDNSu32 remain, const char *ifname, mDNSu32 *CacheUsed)
+mDNSlocal void PrintOneCacheRecordToFD(int fd, const CacheRecord *cr, mDNSu32 slot, const mDNSu32 remain, const char *ifname, mDNSu32 *CacheUsed)
{
- LogMsgNoIdent("%3d %s%8d %-7s%s %-6s%s",
- slot,
- cr->CRActiveQuestion ? "*" : " ",
- remain,
- ifname ? ifname : "-U-",
- (cr->resrec.RecordType == kDNSRecordTypePacketNegative) ? "-" :
- (cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? " " : "+",
- DNSTypeName(cr->resrec.rrtype),
- CRDisplayString(&mDNSStorage, cr));
+ LogToFD(fd, "%3d %s%8d %-7s%s %-6s%s",
+ slot,
+ cr->CRActiveQuestion ? "*" : " ",
+ remain,
+ ifname ? ifname : "-U-",
+ (cr->resrec.RecordType == kDNSRecordTypePacketNegative) ? "-" :
+ (cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? " " : "+",
+ DNSTypeName(cr->resrec.rrtype),
+ CRDisplayString(&mDNSStorage, cr));
(*CacheUsed)++;
}
-mDNSlocal void PrintCachedRecords(const CacheRecord *cr, mDNSu32 slot, const mDNSu32 remain, const char *ifname, mDNSu32 *CacheUsed)
+mDNSlocal void PrintCachedRecordsToFD(int fd, const CacheRecord *cr, mDNSu32 slot, const mDNSu32 remain, const char *ifname, mDNSu32 *CacheUsed)
{
- CacheRecord *nsec;
CacheRecord *soa;
- nsec = cr->nsec;
- // The records that are cached under the main cache record like nsec, soa don't have
- // their own lifetime. If the main cache record expires, they also expire.
- while (nsec)
- {
- PrintOneCacheRecord(nsec, slot, remain, ifname, CacheUsed);
- nsec = nsec->next;
- }
soa = cr->soa;
if (soa)
{
- PrintOneCacheRecord(soa, slot, remain, ifname, CacheUsed);
- }
- if (cr->resrec.AnonInfo)
- {
- ResourceRecord *nsec3 = cr->resrec.AnonInfo->nsec3RR;
- // Even though it is a resource record, we print the sameway
- // as a cache record so that it aligns properly.
- if (nsec3)
- {
- LogMsgNoIdent("%3d %s%8d %-7s%s %-6s%s",
- slot,
- " ",
- remain,
- ifname ? ifname : "-U-",
- (nsec3->RecordType == kDNSRecordTypePacketNegative) ? "-" :
- (nsec3->RecordType & kDNSRecordTypePacketUniqueMask) ? " " : "+",
- DNSTypeName(nsec3->rrtype),
- RRDisplayString(&mDNSStorage, nsec3));
- }
+ PrintOneCacheRecordToFD(fd, soa, slot, remain, ifname, CacheUsed);
}
}
-mDNSlocal char *AnonDataToString(const mDNSu8 *ad, int adlen, char *adstr, int adstrlen)
+mDNSexport void LogMDNSStatisticsToFD(int fd, mDNS *const m)
{
- adstr[0] = 0;
- if (ad)
- {
- int len;
- char *orig = adstr;
+ LogToFD(fd, "--- MDNS Statistics ---");
+
+ LogToFD(fd, "Name Conflicts %u", m->mDNSStats.NameConflicts);
+ LogToFD(fd, "KnownUnique Name Conflicts %u", m->mDNSStats.KnownUniqueNameConflicts);
+ LogToFD(fd, "Duplicate Query Suppressions %u", m->mDNSStats.DupQuerySuppressions);
+ LogToFD(fd, "KA Suppressions %u", m->mDNSStats.KnownAnswerSuppressions);
+ LogToFD(fd, "KA Multiple Packets %u", m->mDNSStats.KnownAnswerMultiplePkts);
+ LogToFD(fd, "Poof Cache Deletions %u", m->mDNSStats.PoofCacheDeletions);
+ LogToFD(fd, "--------------------------------");
+
+ LogToFD(fd, "Multicast packets Sent %u", m->MulticastPacketsSent);
+ LogToFD(fd, "Multicast packets Received %u", m->MPktNum);
+ LogToFD(fd, "Remote Subnet packets %u", m->RemoteSubnet);
+ LogToFD(fd, "QU questions received %u", m->mDNSStats.UnicastBitInQueries);
+ LogToFD(fd, "Normal multicast questions %u", m->mDNSStats.NormalQueries);
+ LogToFD(fd, "Answers for questions %u", m->mDNSStats.MatchingAnswersForQueries);
+ LogToFD(fd, "Unicast responses %u", m->mDNSStats.UnicastResponses);
+ LogToFD(fd, "Multicast responses %u", m->mDNSStats.MulticastResponses);
+ LogToFD(fd, "Unicast response Demotions %u", m->mDNSStats.UnicastDemotedToMulticast);
+ LogToFD(fd, "--------------------------------");
+
+ LogToFD(fd, "Sleeps %u", m->mDNSStats.Sleeps);
+ LogToFD(fd, "Wakeups %u", m->mDNSStats.Wakes);
+ LogToFD(fd, "Interface UP events %u", m->mDNSStats.InterfaceUp);
+ LogToFD(fd, "Interface UP Flap events %u", m->mDNSStats.InterfaceUpFlap);
+ LogToFD(fd, "Interface Down events %u", m->mDNSStats.InterfaceDown);
+ LogToFD(fd, "Interface DownFlap events %u", m->mDNSStats.InterfaceDownFlap);
+ LogToFD(fd, "Cache refresh queries %u", m->mDNSStats.CacheRefreshQueries);
+ LogToFD(fd, "Cache refreshed %u", m->mDNSStats.CacheRefreshed);
+ LogToFD(fd, "Wakeup on Resolves %u", m->mDNSStats.WakeOnResolves);
+}
- // If the caller is lazy to compute the length, we do it for them.
- if (!adlen)
- len = strlen((const char *)ad);
- else
- len = adlen;
-
- // Print the anondata within brackets. Hence, we need space for two
- // brackets and a NULL byte.
- if (len > (adstrlen - 3))
- len = adstrlen - 3;
-
- *adstr++ = '(';
- mDNSPlatformMemCopy(adstr, ad, len);
- adstr[len] = ')';
- adstr[len+1] = 0;
- return orig;
- }
- return adstr;
-}
-
-mDNSexport void LogMDNSStatistics(mDNS *const m)
-{
- LogMsgNoIdent("--- MDNS Statistics ---");
-
- LogMsgNoIdent("Name Conflicts %u", m->mDNSStats.NameConflicts);
- LogMsgNoIdent("KnownUnique Name Conflicts %u", m->mDNSStats.KnownUniqueNameConflicts);
- LogMsgNoIdent("Duplicate Query Suppressions %u", m->mDNSStats.DupQuerySuppressions);
- LogMsgNoIdent("KA Suppressions %u", m->mDNSStats.KnownAnswerSuppressions);
- LogMsgNoIdent("KA Multiple Packets %u", m->mDNSStats.KnownAnswerMultiplePkts);
- LogMsgNoIdent("Poof Cache Deletions %u", m->mDNSStats.PoofCacheDeletions);
- LogMsgNoIdent("--------------------------------");
-
- LogMsgNoIdent("Multicast packets Sent %u", m->MulticastPacketsSent);
- LogMsgNoIdent("Multicast packets Received %u", m->MPktNum);
- LogMsgNoIdent("Remote Subnet packets %u", m->RemoteSubnet);
- LogMsgNoIdent("QU questions received %u", m->mDNSStats.UnicastBitInQueries);
- LogMsgNoIdent("Normal multicast questions %u", m->mDNSStats.NormalQueries);
- LogMsgNoIdent("Answers for questions %u", m->mDNSStats.MatchingAnswersForQueries);
- LogMsgNoIdent("Unicast responses %u", m->mDNSStats.UnicastResponses);
- LogMsgNoIdent("Multicast responses %u", m->mDNSStats.MulticastResponses);
- LogMsgNoIdent("Unicast response Demotions %u", m->mDNSStats.UnicastDemotedToMulticast);
- LogMsgNoIdent("--------------------------------");
-
- LogMsgNoIdent("Sleeps %u", m->mDNSStats.Sleeps);
- LogMsgNoIdent("Wakeups %u", m->mDNSStats.Wakes);
- LogMsgNoIdent("Interface UP events %u", m->mDNSStats.InterfaceUp);
- LogMsgNoIdent("Interface UP Flap events %u", m->mDNSStats.InterfaceUpFlap);
- LogMsgNoIdent("Interface Down events %u", m->mDNSStats.InterfaceDown);
- LogMsgNoIdent("Interface DownFlap events %u", m->mDNSStats.InterfaceDownFlap);
- LogMsgNoIdent("Cache refresh queries %u", m->mDNSStats.CacheRefreshQueries);
- LogMsgNoIdent("Cache refreshed %u", m->mDNSStats.CacheRefreshed);
- LogMsgNoIdent("Wakeup on Resolves %u", m->mDNSStats.WakeOnResolves);
-}
-
-mDNSexport void udsserver_info()
+mDNSexport void udsserver_info_dump_to_fd(int fd)
{
mDNS *const m = &mDNSStorage;
const mDNSs32 now = mDNS_TimeNow(m);
@@ -5752,10 +5793,8 @@ mDNSexport void udsserver_info()
const DNameListElem *d;
const SearchListElem *s;
- LogMsgNoIdent("Timenow 0x%08lX (%d)", (mDNSu32)now, now);
-
- LogMsgNoIdent("------------ Cache -------------");
- LogMsgNoIdent("Slt Q TTL if U Type rdlen");
+ LogToFD(fd, "------------ Cache -------------");
+ LogToFD(fd, "Slt Q TTL if U Type rdlen");
for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
{
for (cg = m->rrcache_hash[slot]; cg; cg=cg->next)
@@ -5767,50 +5806,57 @@ mDNSexport void udsserver_info()
const char *ifname;
mDNSInterfaceID InterfaceID = cr->resrec.InterfaceID;
mDNSu32 *const countPtr = InterfaceID ? &mcastRecordCount : &ucastRecordCount;
- if (!InterfaceID && cr->resrec.rDNSServer && cr->resrec.rDNSServer->scoped)
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ if (!InterfaceID && cr->resrec.dnsservice &&
+ (mdns_dns_service_get_scope(cr->resrec.dnsservice) == mdns_dns_service_scope_interface))
+ {
+ InterfaceID = (mDNSInterfaceID)(uintptr_t)mdns_dns_service_get_interface_index(cr->resrec.dnsservice);
+ }
+#else
+ if (!InterfaceID && cr->resrec.rDNSServer && cr->resrec.rDNSServer->scopeType)
InterfaceID = cr->resrec.rDNSServer->interface;
+#endif
ifname = InterfaceNameForID(m, InterfaceID);
if (cr->CRActiveQuestion) CacheActive++;
- PrintOneCacheRecord(cr, slot, remain, ifname, countPtr);
- PrintCachedRecords(cr, slot, remain, ifname, countPtr);
+ PrintOneCacheRecordToFD(fd, cr, slot, remain, ifname, countPtr);
+ PrintCachedRecordsToFD(fd, cr, slot, remain, ifname, countPtr);
}
}
}
CacheUsed = groupCount + mcastRecordCount + ucastRecordCount;
if (m->rrcache_totalused != CacheUsed)
- LogMsgNoIdent("Cache use mismatch: rrcache_totalused is %lu, true count %lu", m->rrcache_totalused, CacheUsed);
+ LogToFD(fd, "Cache use mismatch: rrcache_totalused is %lu, true count %lu", m->rrcache_totalused, CacheUsed);
if (m->rrcache_active != CacheActive)
- LogMsgNoIdent("Cache use mismatch: rrcache_active is %lu, true count %lu", m->rrcache_active, CacheActive);
- LogMsgNoIdent("Cache size %u entities; %u in use (%u group, %u multicast, %u unicast); %u referenced by active questions",
- m->rrcache_size, CacheUsed, groupCount, mcastRecordCount, ucastRecordCount, CacheActive);
+ LogToFD(fd, "Cache use mismatch: rrcache_active is %lu, true count %lu", m->rrcache_active, CacheActive);
+ LogToFD(fd, "Cache size %u entities; %u in use (%u group, %u multicast, %u unicast); %u referenced by active questions",
+ m->rrcache_size, CacheUsed, groupCount, mcastRecordCount, ucastRecordCount, CacheActive);
- LogMsgNoIdent("--------- Auth Records ---------");
- LogAuthRecords(now, m->ResourceRecords, mDNSNULL);
+ LogToFD(fd, "--------- Auth Records ---------");
+ LogAuthRecordsToFD(fd, now, m->ResourceRecords, mDNSNULL);
- LogMsgNoIdent("--------- LocalOnly, P2P Auth Records ---------");
- LogLocalOnlyAuthRecords(m);
+ LogToFD(fd, "--------- LocalOnly, P2P Auth Records ---------");
+ LogLocalOnlyAuthRecordsToFD(fd, m);
- LogMsgNoIdent("--------- /etc/hosts ---------");
- LogEtcHosts(m);
+ LogToFD(fd, "--------- /etc/hosts ---------");
+ LogEtcHostsToFD(fd, m);
- LogMsgNoIdent("------ Duplicate Records -------");
- LogAuthRecords(now, m->DuplicateRecords, mDNSNULL);
+ LogToFD(fd, "------ Duplicate Records -------");
+ LogAuthRecordsToFD(fd, now, m->DuplicateRecords, mDNSNULL);
- LogMsgNoIdent("----- Auth Records Proxied -----");
- LogAuthRecords(now, m->ResourceRecords, &ProxyA);
+ LogToFD(fd, "----- Auth Records Proxied -----");
+ LogAuthRecordsToFD(fd, now, m->ResourceRecords, &ProxyA);
- LogMsgNoIdent("-- Duplicate Records Proxied ---");
- LogAuthRecords(now, m->DuplicateRecords, &ProxyD);
+ LogToFD(fd, "-- Duplicate Records Proxied ---");
+ LogAuthRecordsToFD(fd, now, m->DuplicateRecords, &ProxyD);
- LogMsgNoIdent("---------- Questions -----------");
- if (!m->Questions) LogMsgNoIdent("<None>");
+ LogToFD(fd, "---------- Questions -----------");
+ if (!m->Questions) LogToFD(fd, "<None>");
else
{
- char anonstr[256];
CacheUsed = 0;
CacheActive = 0;
- LogMsgNoIdent(" Int Next if T NumAns VDNS Qptr DupOf SU SQ Type Name");
+ LogToFD(fd, " Int Next if T NumAns VDNS Qptr DupOf SU SQ Type Name");
for (q = m->Questions; q; q=q->next)
{
mDNSs32 i = q->ThisQInterval / mDNSPlatformOneSecond;
@@ -5818,29 +5864,34 @@ mDNSexport void udsserver_info()
char *ifname = InterfaceNameForID(m, q->InterfaceID);
CacheUsed++;
if (q->ThisQInterval) CacheActive++;
- LogMsgNoIdent("%6d%6d %-7s%s%s %5d 0x%x%x%x%x 0x%p 0x%p %1d %2d %-5s%##s%s%s",
- i, n,
- ifname ? ifname : mDNSOpaque16IsZero(q->TargetQID) ? "" : "-U-",
- mDNSOpaque16IsZero(q->TargetQID) ? (q->LongLived ? "l" : " ") : (q->LongLived ? "L" : "O"),
- PrivateQuery(q) ? "P" : q->ValidationRequired ? "V" : q->ValidatingResponse ? "R" : " ",
- q->CurrentAnswers, q->validDNSServers.l[3], q->validDNSServers.l[2], q->validDNSServers.l[1],
- q->validDNSServers.l[0], q, q->DuplicateOf,
- q->SuppressUnusable, q->SuppressQuery, DNSTypeName(q->qtype), q->qname.c,
- AnonInfoToString(q->AnonInfo, anonstr, sizeof(anonstr)),
- q->DuplicateOf ? " (dup)" : "");
- }
- LogMsgNoIdent("%lu question%s; %lu active", CacheUsed, CacheUsed > 1 ? "s" : "", CacheActive);
- }
-
- LogMsgNoIdent("----- LocalOnly, P2P Questions -----");
- if (!m->LocalOnlyQuestions) LogMsgNoIdent("<None>");
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ LogToFD(fd, "%6d%6d %-7s%s %5d 0x%p 0x%p %1d %2d %-5s%##s%s",
+#else
+ LogToFD(fd, "%6d%6d %-7s%s %5d 0x%08x%08x%08x%08x 0x%p 0x%p %1d %2d %-5s%##s%s",
+#endif
+ i, n,
+ ifname ? ifname : mDNSOpaque16IsZero(q->TargetQID) ? "" : "-U-",
+ mDNSOpaque16IsZero(q->TargetQID) ? (q->LongLived ? "l" : " ") : (q->LongLived ? "L" : "O"),
+ q->CurrentAnswers,
+#if !MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ q->validDNSServers.l[3], q->validDNSServers.l[2], q->validDNSServers.l[1], q->validDNSServers.l[0],
+#endif
+ q, q->DuplicateOf,
+ q->SuppressUnusable, q->Suppressed, DNSTypeName(q->qtype), q->qname.c,
+ q->DuplicateOf ? " (dup)" : "");
+ }
+ LogToFD(fd, "%lu question%s; %lu active", CacheUsed, CacheUsed > 1 ? "s" : "", CacheActive);
+ }
+
+ LogToFD(fd, "----- LocalOnly, P2P Questions -----");
+ if (!m->LocalOnlyQuestions) LogToFD(fd, "<None>");
else for (q = m->LocalOnlyQuestions; q; q=q->next)
- LogMsgNoIdent(" %3s %5d %-6s%##s%s",
- q->InterfaceID == mDNSInterface_LocalOnly ? "LO ": q->InterfaceID == mDNSInterface_BLE ? "BLE": "P2P",
- q->CurrentAnswers, DNSTypeName(q->qtype), q->qname.c, q->DuplicateOf ? " (dup)" : "");
+ LogToFD(fd, " %3s %5d %-6s%##s%s",
+ q->InterfaceID == mDNSInterface_LocalOnly ? "LO ": q->InterfaceID == mDNSInterface_BLE ? "BLE": "P2P",
+ q->CurrentAnswers, DNSTypeName(q->qtype), q->qname.c, q->DuplicateOf ? " (dup)" : "");
- LogMsgNoIdent("---- Active UDS Client Requests ----");
- if (!all_requests) LogMsgNoIdent("<None>");
+ LogToFD(fd, "---- Active UDS Client Requests ----");
+ if (!all_requests) LogToFD(fd, "<None>");
else
{
request_state *req, *r;
@@ -5849,231 +5900,174 @@ mDNSexport void udsserver_info()
if (req->primary) // If this is a subbordinate operation, check that the parent is in the list
{
for (r = all_requests; r && r != req; r=r->next) if (r == req->primary) goto foundparent;
- LogMsgNoIdent("%3d: Orhpan operation %p; parent %p not found in request list", req->sd);
+ LogToFD(fd, "%3d: Orhpan operation %p; parent %p not found in request list", req->sd);
}
// For non-subbordinate operations, and subbordinate operations that have lost their parent, write out their info
- LogClientInfo(req);
-foundparent:;
+ LogClientInfoToFD(fd, req);
+ foundparent:;
}
}
- LogMsgNoIdent("-------- NAT Traversals --------");
- LogMsgNoIdent("ExtAddress %.4a Retry %d Interval %d",
- &m->ExtAddress,
- m->retryGetAddr ? (m->retryGetAddr - now) / mDNSPlatformOneSecond : 0,
- m->retryIntervalGetAddr / mDNSPlatformOneSecond);
+ LogToFD(fd, "-------- NAT Traversals --------");
+ LogToFD(fd, "ExtAddress %.4a Retry %d Interval %d",
+ &m->ExtAddress,
+ m->retryGetAddr ? (m->retryGetAddr - now) / mDNSPlatformOneSecond : 0,
+ m->retryIntervalGetAddr / mDNSPlatformOneSecond);
if (m->NATTraversals)
{
const NATTraversalInfo *nat;
for (nat = m->NATTraversals; nat; nat=nat->next)
{
- LogMsgNoIdent("%p %s Int %5d %s Err %d Retry %5d Interval %5d Expire %5d Req %.4a:%d Ext %.4a:%d",
- nat,
- nat->Protocol ? (nat->Protocol == NATOp_MapTCP ? "TCP" : "UDP") : "ADD",
- mDNSVal16(nat->IntPort),
- (nat->lastSuccessfulProtocol == NATTProtocolNone ? "None " :
- nat->lastSuccessfulProtocol == NATTProtocolNATPMP ? "NAT-PMP " :
- nat->lastSuccessfulProtocol == NATTProtocolUPNPIGD ? "UPnP/IGD" :
- nat->lastSuccessfulProtocol == NATTProtocolPCP ? "PCP " :
- /* else */ "Unknown " ),
- nat->Result,
- nat->retryPortMap ? (nat->retryPortMap - now) / mDNSPlatformOneSecond : 0,
- nat->retryInterval / mDNSPlatformOneSecond,
- nat->ExpiryTime ? (nat->ExpiryTime - now) / mDNSPlatformOneSecond : 0,
- &nat->NewAddress, mDNSVal16(nat->RequestedPort),
- &nat->ExternalAddress, mDNSVal16(nat->ExternalPort));
- }
- }
-
- LogMsgNoIdent("--------- AuthInfoList ---------");
- if (!m->AuthInfoList) LogMsgNoIdent("<None>");
+ LogToFD(fd, "%p %s Int %5d %s Err %d Retry %5d Interval %5d Expire %5d Req %.4a:%d Ext %.4a:%d",
+ nat,
+ nat->Protocol ? (nat->Protocol == NATOp_MapTCP ? "TCP" : "UDP") : "ADD",
+ mDNSVal16(nat->IntPort),
+ (nat->lastSuccessfulProtocol == NATTProtocolNone ? "None " :
+ nat->lastSuccessfulProtocol == NATTProtocolNATPMP ? "NAT-PMP " :
+ nat->lastSuccessfulProtocol == NATTProtocolUPNPIGD ? "UPnP/IGD" :
+ nat->lastSuccessfulProtocol == NATTProtocolPCP ? "PCP " :
+ /* else */ "Unknown " ),
+ nat->Result,
+ nat->retryPortMap ? (nat->retryPortMap - now) / mDNSPlatformOneSecond : 0,
+ nat->retryInterval / mDNSPlatformOneSecond,
+ nat->ExpiryTime ? (nat->ExpiryTime - now) / mDNSPlatformOneSecond : 0,
+ &nat->NewAddress, mDNSVal16(nat->RequestedPort),
+ &nat->ExternalAddress, mDNSVal16(nat->ExternalPort));
+ }
+ }
+
+ LogToFD(fd, "--------- AuthInfoList ---------");
+ if (!m->AuthInfoList) LogToFD(fd, "<None>");
else
{
const DomainAuthInfo *a;
for (a = m->AuthInfoList; a; a = a->next)
{
- LogMsgNoIdent("%##s %##s %##s %d %d %.16a%s",
- a->domain.c, a->keyname.c,
- a->hostname.c, (a->port.b[0] << 8 | a->port.b[1]),
- (a->deltime ? (a->deltime - now) : 0),
- &a->AutoTunnelInnerAddress, a->AutoTunnel ? " AutoTunnel" : "");
+ LogToFD(fd, "%##s %##s %##s %d %d",
+ a->domain.c, a->keyname.c,
+ a->hostname.c, (a->port.b[0] << 8 | a->port.b[1]),
+ (a->deltime ? (a->deltime - now) : 0));
}
}
- #if APPLE_OSX_mDNSResponder
- LogMsgNoIdent("--------- TunnelClients --------");
- if (!m->TunnelClients) LogMsgNoIdent("<None>");
- else
- {
- const ClientTunnel *c;
- for (c = m->TunnelClients; c; c = c->next)
- LogMsgNoIdent("%##s local %.16a %.4a %.16a remote %.16a %.4a %5d %.16a interval %d",
- c->dstname.c, &c->loc_inner, &c->loc_outer, &c->loc_outer6, &c->rmt_inner, &c->rmt_outer, mDNSVal16(c->rmt_outer_port), &c->rmt_outer6, c->q.ThisQInterval);
- }
- #endif // APPLE_OSX_mDNSResponder
-
- LogMsgNoIdent("---------- Misc State ----------");
+ LogToFD(fd, "---------- Misc State ----------");
- LogMsgNoIdent("PrimaryMAC: %.6a", &m->PrimaryMAC);
+ LogToFD(fd, "PrimaryMAC: %.6a", &m->PrimaryMAC);
- LogMsgNoIdent("m->SleepState %d (%s) seq %d",
- m->SleepState,
- m->SleepState == SleepState_Awake ? "Awake" :
- m->SleepState == SleepState_Transferring ? "Transferring" :
- m->SleepState == SleepState_Sleeping ? "Sleeping" : "?",
- m->SleepSeqNum);
+ LogToFD(fd, "m->SleepState %d (%s) seq %d",
+ m->SleepState,
+ m->SleepState == SleepState_Awake ? "Awake" :
+ m->SleepState == SleepState_Transferring ? "Transferring" :
+ m->SleepState == SleepState_Sleeping ? "Sleeping" : "?",
+ m->SleepSeqNum);
- if (!m->SPSSocket) LogMsgNoIdent("Not offering Sleep Proxy Service");
+ if (!m->SPSSocket) LogToFD(fd, "Not offering Sleep Proxy Service");
#ifndef SPC_DISABLED
- else LogMsgNoIdent("Offering Sleep Proxy Service: %#s", m->SPSRecords.RR_SRV.resrec.name->c);
+ else LogToFD(fd, "Offering Sleep Proxy Service: %#s", m->SPSRecords.RR_SRV.resrec.name->c);
#endif
- if (m->ProxyRecords == ProxyA + ProxyD) LogMsgNoIdent("ProxyRecords: %d + %d = %d", ProxyA, ProxyD, ProxyA + ProxyD);
- else LogMsgNoIdent("ProxyRecords: MISMATCH %d + %d = %d ≠ %d", ProxyA, ProxyD, ProxyA + ProxyD, m->ProxyRecords);
+ if (m->ProxyRecords == ProxyA + ProxyD) LogToFD(fd, "ProxyRecords: %d + %d = %d", ProxyA, ProxyD, ProxyA + ProxyD);
+ else LogToFD(fd, "ProxyRecords: MISMATCH %d + %d = %d ≠ %d", ProxyA, ProxyD, ProxyA + ProxyD, m->ProxyRecords);
- LogMsgNoIdent("------ Auto Browse Domains -----");
- if (!AutoBrowseDomains) LogMsgNoIdent("<None>");
- else for (d=AutoBrowseDomains; d; d=d->next) LogMsgNoIdent("%##s", d->name.c);
+ LogToFD(fd, "------ Auto Browse Domains -----");
+ if (!AutoBrowseDomains) LogToFD(fd, "<None>");
+ else for (d=AutoBrowseDomains; d; d=d->next) LogToFD(fd, "%##s", d->name.c);
- LogMsgNoIdent("--- Auto Registration Domains --");
- if (!AutoRegistrationDomains) LogMsgNoIdent("<None>");
- else for (d=AutoRegistrationDomains; d; d=d->next) LogMsgNoIdent("%##s", d->name.c);
+ LogToFD(fd, "--- Auto Registration Domains --");
+ if (!AutoRegistrationDomains) LogToFD(fd, "<None>");
+ else for (d=AutoRegistrationDomains; d; d=d->next) LogToFD(fd, "%##s", d->name.c);
- LogMsgNoIdent("--- Search Domains --");
- if (!SearchList) LogMsgNoIdent("<None>");
+ LogToFD(fd, "--- Search Domains --");
+ if (!SearchList) LogToFD(fd, "<None>");
else
{
for (s=SearchList; s; s=s->next)
{
char *ifname = InterfaceNameForID(m, s->InterfaceID);
- LogMsgNoIdent("%##s %s", s->domain.c, ifname ? ifname : "");
- }
- }
- LogInfo("--- Trust Anchors ---");
- if (!m->TrustAnchors)
- {
- LogInfo("<None>");
- }
- else
- {
- TrustAnchor *ta;
- mDNSu8 fromTimeBuf[64];
- mDNSu8 untilTimeBuf[64];
-
- for (ta=m->TrustAnchors; ta; ta=ta->next)
- {
- mDNSPlatformFormatTime((unsigned long)ta->validFrom, fromTimeBuf, sizeof(fromTimeBuf));
- mDNSPlatformFormatTime((unsigned long)ta->validUntil, untilTimeBuf, sizeof(untilTimeBuf));
- LogInfo("%##s %d %d %d %d %s %s", ta->zone.c, ta->rds.keyTag,
- ta->rds.alg, ta->rds.digestType, ta->digestLen, fromTimeBuf, untilTimeBuf);
+ LogToFD(fd, "%##s %s", s->domain.c, ifname ? ifname : "");
}
}
+ LogMDNSStatisticsToFD(fd, m);
- LogInfo("--- DNSSEC Statistics ---");
+ LogToFD(fd, "---- Task Scheduling Timers ----");
- LogMsgNoIdent("Unicast Cache size %u", m->rrcache_totalused_unicast);
- LogInfo("DNSSEC Cache size %u", m->DNSSECStats.TotalMemUsed);
- if (m->rrcache_totalused_unicast)
- LogInfo("DNSSEC usage percentage %u", ((unsigned long)(m->DNSSECStats.TotalMemUsed * 100))/m->rrcache_totalused_unicast);
- LogInfo("DNSSEC Extra Packets (0 to 2) %u", m->DNSSECStats.ExtraPackets0);
- LogInfo("DNSSEC Extra Packets (3 to 6) %u", m->DNSSECStats.ExtraPackets3);
- LogInfo("DNSSEC Extra Packets (7 to 9) %u", m->DNSSECStats.ExtraPackets7);
- LogInfo("DNSSEC Extra Packets ( >= 10) %u", m->DNSSECStats.ExtraPackets10);
-
- LogInfo("DNSSEC Latency (0 to 4ms) %u", m->DNSSECStats.Latency0);
- LogInfo("DNSSEC Latency (4 to 9ms) %u", m->DNSSECStats.Latency5);
- LogInfo("DNSSEC Latency (10 to 19ms) %u", m->DNSSECStats.Latency10);
- LogInfo("DNSSEC Latency (20 to 49ms) %u", m->DNSSECStats.Latency20);
- LogInfo("DNSSEC Latency (50 to 99ms) %u", m->DNSSECStats.Latency50);
- LogInfo("DNSSEC Latency ( >=100ms) %u", m->DNSSECStats.Latency100);
-
- LogInfo("DNSSEC Secure Status %u", m->DNSSECStats.SecureStatus);
- LogInfo("DNSSEC Insecure Status %u", m->DNSSECStats.InsecureStatus);
- LogInfo("DNSSEC Indeterminate Status %u", m->DNSSECStats.IndeterminateStatus);
- LogInfo("DNSSEC Bogus Status %u", m->DNSSECStats.BogusStatus);
- LogInfo("DNSSEC NoResponse Status %u", m->DNSSECStats.NoResponseStatus);
- LogInfo("DNSSEC Probes sent %u", m->DNSSECStats.NumProbesSent);
- LogInfo("DNSSEC Msg Size (<=1024) %u", m->DNSSECStats.MsgSize0);
- LogInfo("DNSSEC Msg Size (<=2048) %u", m->DNSSECStats.MsgSize1);
- LogInfo("DNSSEC Msg Size (> 2048) %u", m->DNSSECStats.MsgSize2);
-
- LogMDNSStatistics(m);
-
- LogMsgNoIdent("---- Task Scheduling Timers ----");
-
-#if BONJOUR_ON_DEMAND
- LogMsgNoIdent("BonjourEnabled %d", m->BonjourEnabled);
-#endif // BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
+ LogToFD(fd, "BonjourEnabled %d", m->BonjourEnabled);
+#endif
#if APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
- LogMsgNoIdent("EnableBLEBasedDiscovery %d", EnableBLEBasedDiscovery);
- LogMsgNoIdent("DefaultToBLETriggered %d", DefaultToBLETriggered);
+ LogToFD(fd, "EnableBLEBasedDiscovery %d", EnableBLEBasedDiscovery);
+ LogToFD(fd, "DefaultToBLETriggered %d", DefaultToBLETriggered);
#endif // APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
if (!m->NewQuestions)
- LogMsgNoIdent("NewQuestion <NONE>");
+ LogToFD(fd, "NewQuestion <NONE>");
else
- LogMsgNoIdent("NewQuestion DelayAnswering %d %d %##s (%s)",
- m->NewQuestions->DelayAnswering, m->NewQuestions->DelayAnswering-now,
- m->NewQuestions->qname.c, DNSTypeName(m->NewQuestions->qtype));
+ LogToFD(fd, "NewQuestion DelayAnswering %d %d %##s (%s)",
+ m->NewQuestions->DelayAnswering, m->NewQuestions->DelayAnswering-now,
+ m->NewQuestions->qname.c, DNSTypeName(m->NewQuestions->qtype));
if (!m->NewLocalOnlyQuestions)
- LogMsgNoIdent("NewLocalOnlyQuestions <NONE>");
+ LogToFD(fd, "NewLocalOnlyQuestions <NONE>");
else
- LogMsgNoIdent("NewLocalOnlyQuestions %##s (%s)",
- m->NewLocalOnlyQuestions->qname.c, DNSTypeName(m->NewLocalOnlyQuestions->qtype));
+ LogToFD(fd, "NewLocalOnlyQuestions %##s (%s)",
+ m->NewLocalOnlyQuestions->qname.c, DNSTypeName(m->NewLocalOnlyQuestions->qtype));
if (!m->NewLocalRecords)
- LogMsgNoIdent("NewLocalRecords <NONE>");
+ LogToFD(fd, "NewLocalRecords <NONE>");
else
- LogMsgNoIdent("NewLocalRecords %02X %s", m->NewLocalRecords->resrec.RecordType, ARDisplayString(m, m->NewLocalRecords));
-
- LogMsgNoIdent("SPSProxyListChanged%s", m->SPSProxyListChanged ? "" : " <NONE>");
- LogMsgNoIdent("LocalRemoveEvents%s", m->LocalRemoveEvents ? "" : " <NONE>");
- LogMsgNoIdent("m->AutoTunnelRelayAddr %.16a", &m->AutoTunnelRelayAddr);
- LogMsgNoIdent("m->WABBrowseQueriesCount %d", m->WABBrowseQueriesCount);
- LogMsgNoIdent("m->WABLBrowseQueriesCount %d", m->WABLBrowseQueriesCount);
- LogMsgNoIdent("m->WABRegQueriesCount %d", m->WABRegQueriesCount);
- LogMsgNoIdent("m->AutoTargetServices %d", m->AutoTargetServices);
+ LogToFD(fd, "NewLocalRecords %02X %s", m->NewLocalRecords->resrec.RecordType, ARDisplayString(m, m->NewLocalRecords));
+
+ LogToFD(fd, "SPSProxyListChanged%s", m->SPSProxyListChanged ? "" : " <NONE>");
+ LogToFD(fd, "LocalRemoveEvents%s", m->LocalRemoveEvents ? "" : " <NONE>");
+ LogToFD(fd, "m->WABBrowseQueriesCount %d", m->WABBrowseQueriesCount);
+ LogToFD(fd, "m->WABLBrowseQueriesCount %d", m->WABLBrowseQueriesCount);
+ LogToFD(fd, "m->WABRegQueriesCount %d", m->WABRegQueriesCount);
+ LogToFD(fd, "m->AutoTargetServices %u", m->AutoTargetServices);
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ LogToFD(fd, "m->AutoTargetAWDLIncludedCount %u", m->AutoTargetAWDLIncludedCount);
+ LogToFD(fd, "m->AutoTargetAWDLOnlyCount %u", m->AutoTargetAWDLOnlyCount);
+#endif
- LogMsgNoIdent(" ABS (hex) ABS (dec) REL (hex) REL (dec)");
- LogMsgNoIdent("m->timenow %08X %11d", now, now);
- LogMsgNoIdent("m->timenow_adjust %08X %11d", m->timenow_adjust, m->timenow_adjust);
- LogTimer("m->NextScheduledEvent ", m->NextScheduledEvent);
+ LogToFD(fd, " ABS (hex) ABS (dec) REL (hex) REL (dec)");
+ LogToFD(fd, "m->timenow %08X %11d", now, now);
+ LogToFD(fd, "m->timenow_adjust %08X %11d", m->timenow_adjust, m->timenow_adjust);
+ LogTimerToFD(fd, "m->NextScheduledEvent ", m->NextScheduledEvent);
#ifndef UNICAST_DISABLED
- LogTimer("m->NextuDNSEvent ", m->NextuDNSEvent);
- LogTimer("m->NextSRVUpdate ", m->NextSRVUpdate);
- LogTimer("m->NextScheduledNATOp ", m->NextScheduledNATOp);
- LogTimer("m->retryGetAddr ", m->retryGetAddr);
+ LogTimerToFD(fd, "m->NextuDNSEvent ", m->NextuDNSEvent);
+ LogTimerToFD(fd, "m->NextSRVUpdate ", m->NextSRVUpdate);
+ LogTimerToFD(fd, "m->NextScheduledNATOp ", m->NextScheduledNATOp);
+ LogTimerToFD(fd, "m->retryGetAddr ", m->retryGetAddr);
#endif
- LogTimer("m->NextCacheCheck ", m->NextCacheCheck);
- LogTimer("m->NextScheduledSPS ", m->NextScheduledSPS);
- LogTimer("m->NextScheduledKA ", m->NextScheduledKA);
+ LogTimerToFD(fd, "m->NextCacheCheck ", m->NextCacheCheck);
+ LogTimerToFD(fd, "m->NextScheduledSPS ", m->NextScheduledSPS);
+ LogTimerToFD(fd, "m->NextScheduledKA ", m->NextScheduledKA);
-#if BONJOUR_ON_DEMAND
- LogTimer("m->NextBonjourDisableTime ", m->NextBonjourDisableTime);
-#endif // BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
+ LogTimerToFD(fd, "m->NextBonjourDisableTime ", m->NextBonjourDisableTime);
+#endif
- LogTimer("m->NextScheduledSPRetry ", m->NextScheduledSPRetry);
- LogTimer("m->DelaySleep ", m->DelaySleep);
+ LogTimerToFD(fd, "m->NextScheduledSPRetry ", m->NextScheduledSPRetry);
+ LogTimerToFD(fd, "m->DelaySleep ", m->DelaySleep);
- LogTimer("m->NextScheduledQuery ", m->NextScheduledQuery);
- LogTimer("m->NextScheduledProbe ", m->NextScheduledProbe);
- LogTimer("m->NextScheduledResponse", m->NextScheduledResponse);
+ LogTimerToFD(fd, "m->NextScheduledQuery ", m->NextScheduledQuery);
+ LogTimerToFD(fd, "m->NextScheduledProbe ", m->NextScheduledProbe);
+ LogTimerToFD(fd, "m->NextScheduledResponse", m->NextScheduledResponse);
- LogTimer("m->SuppressSending ", m->SuppressSending);
- LogTimer("m->SuppressProbes ", m->SuppressProbes);
- LogTimer("m->ProbeFailTime ", m->ProbeFailTime);
- LogTimer("m->DelaySleep ", m->DelaySleep);
- LogTimer("m->SleepLimit ", m->SleepLimit);
- LogTimer("m->NextScheduledStopTime ", m->NextScheduledStopTime);
+ LogTimerToFD(fd, "m->SuppressSending ", m->SuppressSending);
+ LogTimerToFD(fd, "m->SuppressProbes ", m->SuppressProbes);
+ LogTimerToFD(fd, "m->ProbeFailTime ", m->ProbeFailTime);
+ LogTimerToFD(fd, "m->DelaySleep ", m->DelaySleep);
+ LogTimerToFD(fd, "m->SleepLimit ", m->SleepLimit);
+ LogTimerToFD(fd, "m->NextScheduledStopTime ", m->NextScheduledStopTime);
}
-#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
-mDNSexport void uds_validatelists(void)
+#if MDNS_MALLOC_DEBUGGING
+mDNSlocal void udsserver_validatelists(void *context)
{
const request_state *req, *p;
+ (void)context; // unused
for (req = all_requests; req; req=req->next)
{
if (req->next == (request_state *)~0 || (req->sd < 0 && req->sd != -2))
@@ -6138,7 +6132,7 @@ mDNSexport void uds_validatelists(void)
if (d->next == (DNameListElem *)~0 || d->name.c[0] > 63)
LogMemCorruption("AutoRegistrationDomains: %p is garbage (%d)", d, d->name.c[0]);
}
-#endif // APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
+#endif // MDNS_MALLOC_DEBUGGING
mDNSlocal int send_msg(request_state *const req)
{
@@ -6223,6 +6217,8 @@ mDNSexport mDNSs32 udsserver_idle(mDNSs32 nextevent)
if (nextevent - now > mDNSPlatformOneSecond)
nextevent = now + mDNSPlatformOneSecond;
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u] Could not send all replies. Will try again in %d ticks.", r->request_id, nextevent - now);
if (mDNSStorage.SleepState != SleepState_Awake)
r->time_blocked = 0;
else if (!r->time_blocked)
@@ -6264,10 +6260,10 @@ struct CompileTimeAssertionChecks_uds_daemon
// Check our structures are reasonable sizes. Including overly-large buffers, or embedding
// other overly-large structures instead of having a pointer to them, can inadvertently
// cause structure sizes (and therefore memory usage) to balloon unreasonably.
- char sizecheck_request_state [(sizeof(request_state) <= 3696) ? 1 : -1];
+ char sizecheck_request_state [(sizeof(request_state) <= 3880) ? 1 : -1];
char sizecheck_registered_record_entry[(sizeof(registered_record_entry) <= 60) ? 1 : -1];
char sizecheck_service_instance [(sizeof(service_instance) <= 6552) ? 1 : -1];
- char sizecheck_browser_t [(sizeof(browser_t) <= 1432) ? 1 : -1];
+ char sizecheck_browser_t [(sizeof(browser_t) <= 1480) ? 1 : -1];
char sizecheck_reply_hdr [(sizeof(reply_hdr) <= 12) ? 1 : -1];
char sizecheck_reply_state [(sizeof(reply_state) <= 64) ? 1 : -1];
};
diff --git a/usr/src/contrib/mDNSResponder/mDNSShared/uds_daemon.h b/usr/src/contrib/mDNSResponder/mDNSShared/uds_daemon.h
index dc7d9ac26b..d9210579fd 100644
--- a/usr/src/contrib/mDNSResponder/mDNSShared/uds_daemon.h
+++ b/usr/src/contrib/mDNSResponder/mDNSShared/uds_daemon.h
@@ -1,6 +1,6 @@
/* -*- Mode: C; tab-width: 4 -*-
*
- * Copyright (c) 2002-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2002-2020 Apple Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,6 +20,10 @@
#include "mDNSEmbeddedAPI.h"
#include "dnssd_ipc.h"
+#include "ClientRequests.h"
+#if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
+#include "mdns_private.h"
+#endif
/* Client request: */
@@ -97,9 +101,15 @@ struct request_state
mDNSu8 uuid[UUID_SIZE];
mDNSBool validUUID;
dnssd_sock_t errsd;
+#if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
+ audit_token_t audit_token;
+#endif
mDNSu32 uid;
+ mDNSu32 request_id;
void * platform_data;
-
+#if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
+ mdns_trust_t trust;
+#endif
// Note: On a shared connection these fields in the primary structure, including hdr, are re-used
// for each new request. This is because, until we've read the ipc_msg_hdr to find out what the
// operation is, we don't know if we're going to need to allocate a new request_state or not.
@@ -119,6 +129,9 @@ struct request_state
req_termination_fn terminate;
DNSServiceFlags flags;
mDNSu32 interfaceIndex;
+#if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
+ mdns_dns_service_id_t custom_service_id;
+#endif
union
{
@@ -130,7 +143,6 @@ struct request_state
mDNSBool ForceMCast;
domainname regtype;
browser_t *browsers;
- const mDNSu8 *AnonData;
} browser;
struct
{
@@ -147,23 +159,10 @@ struct request_state
mDNSBool autorename; // Set if this client wants us to automatically rename on conflict
mDNSBool allowremotequery; // Respond to unicast queries from outside the local link?
int num_subtypes;
- mDNSBool AnonData;
service_instance *instances;
} servicereg;
struct
{
- mDNSInterfaceID interface_id;
- mDNSu32 flags;
- mDNSu32 protocol;
- DNSQuestion q4;
- DNSQuestion *q42;
- DNSQuestion q6;
- DNSQuestion *q62;
- mDNSu8 v4ans;
- mDNSu8 v6ans;
- } addrinfo;
- struct
- {
mDNSIPPort ReqExt; // External port we originally requested, for logging purposes
NATTraversalInfo NATinfo;
} pm;
@@ -176,12 +175,6 @@ struct request_state
} enumeration;
struct
{
- DNSQuestion q;
- DNSQuestion *q2;
- mDNSu8 ans;
- } queryrecord;
- struct
- {
DNSQuestion qtxt;
DNSQuestion qsrv;
const ResourceRecord *txt;
@@ -189,6 +182,8 @@ struct request_state
mDNSs32 ReportTime;
mDNSBool external_advertise;
} resolve;
+ GetAddrInfoClientRequest addrinfo;
+ QueryRecordClientRequest queryrecord;
} u;
};
@@ -213,11 +208,11 @@ typedef struct reply_state
#define SRS_PORT(S) mDNSVal16((S)->RR_SRV.resrec.rdata->u.srv.port)
-#define LogTimer(MSG,T) LogMsgNoIdent( MSG " %08X %11d %08X %11d", (T), (T), (T)-now, (T)-now)
+#define LogTimerToFD(FILE_DESCRIPTOR, MSG, T) LogToFD((FILE_DESCRIPTOR), MSG " %08X %11d %08X %11d", (T), (T), (T)-now, (T)-now)
-extern int udsserver_init(dnssd_sock_t skts[], mDNSu32 count);
+extern int udsserver_init(dnssd_sock_t skts[], size_t count);
extern mDNSs32 udsserver_idle(mDNSs32 nextevent);
-extern void udsserver_info(void); // print out info about current state
+extern void udsserver_info_dump_to_fd(int fd);
extern void udsserver_handle_configchange(mDNS *const m);
extern int udsserver_exit(void); // should be called prior to app exit
extern void LogMcastStateInfo(mDNSBool mflag, mDNSBool start, mDNSBool mstatelog);
@@ -228,7 +223,7 @@ extern void LogMcastStateInfo(mDNSBool mflag, mDNSBool start, mDNSBool mstatelog
/* Routines that uds_daemon expects to link against: */
-typedef void (*udsEventCallback)(int fd, short filter, void *context);
+typedef void (*udsEventCallback)(int fd, void *context);
extern mStatus udsSupportAddFDToEventLoop(dnssd_sock_t fd, udsEventCallback callback, void *context, void **platform_data);
extern int udsSupportReadFD(dnssd_sock_t fd, char* buf, int len, int flags, void *platform_data);
extern mStatus udsSupportRemoveFDFromEventLoop(dnssd_sock_t fd, void *platform_data); // Note: This also CLOSES the file descriptor as well
@@ -241,36 +236,10 @@ extern mDNS mDNSStorage;
extern DNameListElem *AutoRegistrationDomains;
extern DNameListElem *AutoBrowseDomains;
-extern mDNSs32 ChopSubTypes(char *regtype, char **AnonData);
-extern AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p, char **AnonData);
extern int CountExistingRegistrations(domainname *srv, mDNSIPPort port);
-extern mDNSBool callExternalHelpers(mDNSInterfaceID InterfaceID, const domainname *const domain, DNSServiceFlags flags);
extern void FreeExtraRR(mDNS *const m, AuthRecord *const rr, mStatus result);
extern int CountPeerRegistrations(ServiceRecordSet *const srs);
-#if APPLE_OSX_mDNSResponder
-
-// D2D interface support
-extern void external_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags);
-extern void external_stop_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags);
-extern void external_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags);
-extern void external_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags);
-extern void external_start_resolving_service(mDNSInterfaceID InterfaceID, const domainname *const fqdn, DNSServiceFlags flags);
-extern void external_stop_resolving_service(mDNSInterfaceID InterfaceID, const domainname *const fqdn, DNSServiceFlags flags);
-extern void external_connection_release(const domainname *instance);
-
-#else // APPLE_OSX_mDNSResponder
-
-#define external_start_browsing_for_service(A,B,C,D) (void)(A)
-#define external_stop_browsing_for_service(A,B,C,D) (void)(A)
-#define external_start_advertising_service(A,B) (void)(A)
-#define external_stop_advertising_service(A,B) do { (void)(A); (void)(B); } while (0)
-#define external_start_resolving_service(A,B,C) (void)(A)
-#define external_stop_resolving_service(A,B,C) (void)(A)
-#define external_connection_release(A) (void)(A)
-
-#endif // APPLE_OSX_mDNSResponder
-
extern const char mDNSResponderVersionString_SCCS[];
#define mDNSResponderVersionString (mDNSResponderVersionString_SCCS+5)
diff --git a/usr/src/lib/brand/lx/lx_init/lxinit.c b/usr/src/lib/brand/lx/lx_init/lxinit.c
index 983318c7eb..5f98d4598e 100644
--- a/usr/src/lib/brand/lx/lx_init/lxinit.c
+++ b/usr/src/lib/brand/lx/lx_init/lxinit.c
@@ -490,11 +490,34 @@ lxi_iface_ipv6_link_local(const char *iface)
return (0);
}
+static int lxi_route_send_msg(struct rt_msghdr *rtm)
+{
+ int sockfd, len;
+
+ if ((sockfd = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
+ lxi_warn("socket(PF_ROUTE): %s\n", strerror(errno));
+ return (-1);
+ }
+
+ if ((len = write(sockfd, (const void *)rtm, rtm->rtm_msglen)) < 0) {
+ lxi_warn("could not write rtmsg: %s", strerror(errno));
+ close(sockfd);
+ return (-1);
+ } else if (len < rtm->rtm_msglen) {
+ lxi_warn("write() rtmsg incomplete");
+ close(sockfd);
+ return (-1);
+ }
+
+ close(sockfd);
+ return (0);
+}
+
static int
lxi_iface_gateway(const char *iface, const char *dst, int dstpfx,
- const char *gwaddr)
+ const char *gwaddr, boolean_t llroute)
{
- int idx, len, sockfd;
+ int idx;
char rtbuf[RTMBUFSZ];
struct rt_msghdr *rtm = (struct rt_msghdr *)rtbuf;
struct sockaddr_in *dst_sin = (struct sockaddr_in *)
@@ -504,7 +527,10 @@ lxi_iface_gateway(const char *iface, const char *dst, int dstpfx,
(void) bzero(rtm, RTMBUFSZ);
rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
- rtm->rtm_flags = RTF_UP | RTF_STATIC | RTF_GATEWAY;
+
+ if (!llroute)
+ rtm->rtm_flags = RTF_UP | RTF_STATIC | RTF_GATEWAY;
+
rtm->rtm_msglen = sizeof (rtbuf);
rtm->rtm_pid = getpid();
rtm->rtm_type = RTM_ADD;
@@ -516,6 +542,15 @@ lxi_iface_gateway(const char *iface, const char *dst, int dstpfx,
* which represents the default gateway. If we were passed a more
* specific destination network, use that instead.
*/
+
+ if (dstpfx == -1) {
+ /*
+ * no prefix was specified; assume a prefix length of 32,
+ * which seems in line with the behavior of vmadm.
+ */
+ dstpfx = 32;
+ }
+
dst_sin->sin_family = AF_INET;
netmask_sin->sin_family = AF_INET;
if (dst != NULL) {
@@ -543,23 +578,7 @@ lxi_iface_gateway(const char *iface, const char *dst, int dstpfx,
rtm->rtm_index = idx;
}
- if ((sockfd = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
- lxi_warn("socket(PF_ROUTE): %s\n", strerror(errno));
- return (-1);
- }
-
- if ((len = write(sockfd, rtbuf, rtm->rtm_msglen)) < 0) {
- lxi_warn("could not write rtmsg: %s", strerror(errno));
- close(sockfd);
- return (-1);
- } else if (len < rtm->rtm_msglen) {
- lxi_warn("write() rtmsg incomplete");
- close(sockfd);
- return (-1);
- }
-
- close(sockfd);
- return (0);
+ return (lxi_route_send_msg(rtm));
}
static void
@@ -634,7 +653,7 @@ lxi_net_setup(zone_dochandle_t handle)
while (zonecfg_getnwifent(handle, &lookup) == Z_OK) {
const char *iface = lookup.zone_nwif_physical;
struct zone_res_attrtab *attrs = lookup.zone_nwif_attrp;
- const char *ipaddrs, *primary, *gateway;
+ const char *ipaddrs;
char ipaddrs_copy[MAXNAMELEN], cidraddr[BUFSIZ],
*ipaddr, *tmp, *lasts;
boolean_t first_ipv4_configured = B_FALSE;
@@ -684,12 +703,6 @@ lxi_net_setup(zone_dochandle_t handle)
"to interface %s", ipaddr, iface);
}
}
-
- if (zone_find_attr(attrs, "primary", &primary) == 0 &&
- strncmp(primary, "true", MAXNAMELEN) == 0 &&
- zone_find_attr(attrs, "gateway", &gateway) == 0) {
- lxi_iface_gateway(iface, NULL, 0, gateway);
- }
}
if (do_addrconf) {
@@ -700,31 +713,52 @@ lxi_net_setup(zone_dochandle_t handle)
}
static void
-lxi_net_static_route(const char *line)
+lxi_net_setup_gateways(zone_dochandle_t handle)
{
- /*
- * Each static route line is a string of the form:
- *
- * "10.77.77.2|10.1.1.0/24|false"
- *
- * i.e. gateway address, destination network, and whether this is
- * a "link local" route or a next hop route.
- */
- custr_t *cu = NULL;
- char *gw = NULL, *dst = NULL;
- int pfx = -1;
- int i;
+ struct zone_nwiftab lookup;
- if (custr_alloc(&cu) != 0) {
- lxi_err("custr_alloc failure");
+ if (zonecfg_setnwifent(handle) != Z_OK)
+ return;
+
+ while (zonecfg_getnwifent(handle, &lookup) == Z_OK) {
+ const char *iface = lookup.zone_nwif_physical;
+ struct zone_res_attrtab *attrs = lookup.zone_nwif_attrp;
+ const char *primary, *gateway;
+
+ if (zone_find_attr(attrs, "primary", &primary) == 0 &&
+ strcmp(primary, "true") == 0 &&
+ zone_find_attr(attrs, "gateway", &gateway) == 0) {
+ lxi_iface_gateway(iface, NULL, 0, gateway, B_FALSE);
+ }
}
+ (void) zonecfg_endnwifent(handle);
+}
+
+/*
+ * Parse a static route line string of the form:
+ *
+ * "10.77.77.2|10.1.1.0/24|false"
+ *
+ * i.e. gateway address, destination network, and whether this is
+ * a "link local" route or a next hop route.
+ */
+static void
+lxi_parse_route_line(const char *line, custr_t *cu, char *gw, char *dst,
+ int *pfx, size_t gwlen, size_t dstlen)
+{
+ int i;
+ boolean_t havegw = B_FALSE, havedst = B_FALSE, nopfx = B_FALSE;
+
for (i = 0; line[i] != '\0'; i++) {
- if (gw == NULL) {
+ if (!havegw) {
if (line[i] == '|') {
- if ((gw = strdup(custr_cstr(cu))) == NULL) {
- lxi_err("strdup failure");
- }
+ if (strlcpy(gw, custr_cstr(cu), gwlen)
+ >= gwlen) {
+ lxi_err("strlcpy failure");
+ } else {
+ havegw = B_TRUE;
+ }
custr_reset(cu);
} else {
if (custr_appendc(cu, line[i]) != 0) {
@@ -734,10 +768,16 @@ lxi_net_static_route(const char *line)
continue;
}
- if (dst == NULL) {
- if (line[i] == '/') {
- if ((dst = strdup(custr_cstr(cu))) == NULL) {
- lxi_err("strdup failure");
+ if (!havedst) {
+ if (line[i] == '/' || line[i] == '|') {
+ if ((strlcpy(dst, custr_cstr(cu), dstlen))
+ >= dstlen) {
+ lxi_err("strlcpy failure");
+ } else {
+ havedst = B_TRUE;
+ if (line[i] == '|') {
+ nopfx = B_TRUE;
+ }
}
custr_reset(cu);
} else {
@@ -748,9 +788,9 @@ lxi_net_static_route(const char *line)
continue;
}
- if (pfx == -1) {
+ if (*pfx == -1 && !nopfx) {
if (line[i] == '|') {
- pfx = atoi(custr_cstr(cu));
+ *pfx = atoi(custr_cstr(cu));
custr_reset(cu);
} else {
if (custr_appendc(cu, line[i]) != 0) {
@@ -764,26 +804,59 @@ lxi_net_static_route(const char *line)
lxi_err("custr_appendc failure");
}
}
+}
- /*
- * We currently only support "next hop" routes, so ensure that
- * "linklocal" is false:
- */
- if (strcmp(custr_cstr(cu), "false") != 0) {
- lxi_warn("invalid static route: %s", line);
+static void
+lxi_net_process_route_line(const char *line, boolean_t llonly)
+{
+ custr_t *cu = NULL;
+ int pfx = -1;
+ char gw[INET6_ADDRSTRLEN];
+ char dst[INET6_ADDRSTRLEN];
+
+ if (custr_alloc(&cu) != 0) {
+ lxi_err("custr_alloc failure");
}
- if (lxi_iface_gateway(NULL, dst, pfx, gw) != 0) {
- lxi_err("failed to add route: %s/%d -> %s", dst, pfx, gw);
+ lxi_parse_route_line(line, cu, gw, dst, &pfx, sizeof (gw),
+ sizeof (dst));
+
+ if (llonly && strcmp(custr_cstr(cu), "true") == 0) {
+ if (lxi_iface_gateway(NULL, dst, pfx, gw, B_TRUE) != 0) {
+ lxi_err("failed to add link-local route: %s/%d -> %s",
+ dst, pfx, gw);
+ }
+ } else if (!llonly && strcmp(custr_cstr(cu), "false") == 0) {
+ if (lxi_iface_gateway(NULL, dst, pfx, gw, B_FALSE) != 0) {
+ lxi_err("failed to add next-hop route: %s/%d -> %s",
+ dst, pfx, gw);
+ }
+ } else if (strcmp(custr_cstr(cu), "true") != 0 &&
+ strcmp(custr_cstr(cu), "false") != 0) {
+ /*
+ * try to be helpful when we run into something we don't expect.
+ */
+ lxi_warn("skipping unknown static route defined in line %s, "
+ " parsed link-local flag=%s", line, custr_cstr(cu));
}
custr_free(cu);
- free(gw);
- free(dst);
}
static void
-lxi_net_static_routes(void)
+lxi_net_static_route(const char *line)
+{
+ lxi_net_process_route_line(line, B_FALSE);
+}
+
+static void
+lxi_net_linklocal_route(const char *line)
+{
+ lxi_net_process_route_line(line, B_TRUE);
+}
+
+static void
+lxi_run_routeinfo(void * callback)
{
const char *cmd = "/native/usr/lib/brand/lx/routeinfo";
char *const argv[] = { "routeinfo", NULL };
@@ -796,7 +869,8 @@ lxi_net_static_routes(void)
/*
* This binary is (potentially) shipped from another
* consolidation. If it does not exist, then the platform does
- * not currently support static routes for LX-branded zones.
+ * not currently support link-local or static routes for
+ * LX-branded zones.
*/
return;
}
@@ -807,12 +881,25 @@ lxi_net_static_routes(void)
* is complete.
*/
if (run_command(cmd, argv, envp, errbuf, sizeof (errbuf),
- lxi_net_static_route, &code) != 0 || code != 0) {
+ callback, &code) != 0 || code != 0) {
lxi_err("failed to run \"%s\": %s", cmd, errbuf);
}
}
static void
+lxi_net_linklocal_routes(void)
+{
+ lxi_run_routeinfo(lxi_net_linklocal_route);
+}
+
+
+static void
+lxi_net_static_routes(void)
+{
+ lxi_run_routeinfo(lxi_net_static_route);
+}
+
+static void
lxi_config_close(zone_dochandle_t handle)
{
zonecfg_fini_handle(handle);
@@ -917,6 +1004,10 @@ main(int argc, char *argv[])
handle = lxi_config_open();
lxi_net_loopback();
lxi_net_setup(handle);
+
+ lxi_net_linklocal_routes();
+ lxi_net_setup_gateways(handle);
+
lxi_config_close(handle);
lxi_net_static_routes();
diff --git a/usr/src/lib/libc/Makefile.targ b/usr/src/lib/libc/Makefile.targ
index 9b2d6d35bd..fceb9b27b4 100644
--- a/usr/src/lib/libc/Makefile.targ
+++ b/usr/src/lib/libc/Makefile.targ
@@ -320,7 +320,7 @@ pics/%.o: $(LIBCBASE)/../port/threads/%.d $(THREADSOBJS:%=pics/%)
# assym rules
-LDFLAGS.native = $(LDASSERTS) $(ZASSERTDEFLIB)=libc.so $(BDIRECT)
+LDFLAGS.native = $(LDASSERTS) $(BDIRECT)
#
# genassym is a funny fish: it's run on the build machine, so should use the
diff --git a/usr/src/lib/libc/inc/libc.h b/usr/src/lib/libc/inc/libc.h
index 90a2859b33..98872ac161 100644
--- a/usr/src/lib/libc/inc/libc.h
+++ b/usr/src/lib/libc/inc/libc.h
@@ -222,6 +222,11 @@ extern int _so_getsockopt(int, int, int, char *, int *);
extern int lsign(dl_t);
/*
+ * defined in getctxt.c
+ */
+extern int _getcontext(ucontext_t *) __RETURNS_TWICE;
+
+/*
* defined in ucontext.s
*/
extern int __getcontext(ucontext_t *);
diff --git a/usr/src/lib/libc/sparc/Makefile.com b/usr/src/lib/libc/sparc/Makefile.com
index 217cd58dc8..2b20606aa6 100644
--- a/usr/src/lib/libc/sparc/Makefile.com
+++ b/usr/src/lib/libc/sparc/Makefile.com
@@ -1381,7 +1381,9 @@ $(ASSYMDEP_OBJS:%=pics/%): assym.h
assym.h := CFLAGS += $(CCGDEBUG)
GENASSYM_C = $(LIBCDIR)/$(MACH)/genassym.c
-LDFLAGS.native = $(LDASSERTS) $(ZASSERTDEFLIB)=libc.so $(BDIRECT)
+LDFLAGS.native = $(LDASSERTS) $(BDIRECT)
+
+genassym := NATIVE_LIBS += libc.so
genassym: $(GENASSYM_C)
$(NATIVECC) $(NATIVE_CFLAGS) -I$(LIBCBASE)/inc -I$(LIBCDIR)/inc \
diff --git a/usr/src/lib/libc/sparc/fp/_D_cplx_mul.c b/usr/src/lib/libc/sparc/fp/_D_cplx_mul.c
index 6e32418f72..bfb92e1789 100644
--- a/usr/src/lib/libc/sparc/fp/_D_cplx_mul.c
+++ b/usr/src/lib/libc/sparc/fp/_D_cplx_mul.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* _D_cplx_mul(z, w) returns z * w with infinities handled according
* to C99.
@@ -82,7 +80,7 @@ testinf(double x)
double _Complex
_D_cplx_mul(double _Complex z, double _Complex w)
{
- double _Complex v;
+ double _Complex v = 0;
double a, b, c, d, x, y;
int recalc, i, j;
diff --git a/usr/src/lib/libc/sparc/fp/_F_cplx_mul.c b/usr/src/lib/libc/sparc/fp/_F_cplx_mul.c
index f4073e9327..026a60c7a4 100644
--- a/usr/src/lib/libc/sparc/fp/_F_cplx_mul.c
+++ b/usr/src/lib/libc/sparc/fp/_F_cplx_mul.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* _F_cplx_mul(z, w) returns z * w with infinities handled according
* to C99.
@@ -79,7 +77,7 @@ testinff(float x)
float _Complex
_F_cplx_mul(float _Complex z, float _Complex w)
{
- float _Complex v;
+ float _Complex v = 0;
float a, b, c, d;
double x, y;
int recalc, i, j;
diff --git a/usr/src/lib/libc/sparc/fp/_Q_cplx_div.c b/usr/src/lib/libc/sparc/fp/_Q_cplx_div.c
index b529c5eecf..8740c42f54 100644
--- a/usr/src/lib/libc/sparc/fp/_Q_cplx_div.c
+++ b/usr/src/lib/libc/sparc/fp/_Q_cplx_div.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* On SPARC V8, _Q_cplx_div(v, z, w) sets *v = *z / *w with infin-
* ities handling according to C99.
@@ -85,7 +83,7 @@ testinfl(long double x)
long double _Complex
_Q_cplx_div(const long double _Complex *z, const long double _Complex *w)
{
- long double _Complex v;
+ long double _Complex v = 0;
#else
void
_Q_cplx_div(long double _Complex *v, const long double _Complex *z,
diff --git a/usr/src/lib/libc/sparc/fp/_Q_cplx_div_ix.c b/usr/src/lib/libc/sparc/fp/_Q_cplx_div_ix.c
index 2d9c18ba02..fa2b595406 100644
--- a/usr/src/lib/libc/sparc/fp/_Q_cplx_div_ix.c
+++ b/usr/src/lib/libc/sparc/fp/_Q_cplx_div_ix.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* On SPARC V8, _Q_cplx_div_ix(v, b, w) sets *v = (I * *b / *w) with
* infinities handling according to C99.
@@ -80,7 +78,7 @@ testinfl(long double x)
long double _Complex
_Q_cplx_div_ix(const long double *pb, const long double _Complex *w)
{
- long double _Complex v;
+ long double _Complex v = 0;
#else
void
_Q_cplx_div_ix(long double _Complex *v, const long double *pb,
diff --git a/usr/src/lib/libc/sparc/fp/_Q_cplx_div_rx.c b/usr/src/lib/libc/sparc/fp/_Q_cplx_div_rx.c
index 80f050bd94..a500db400f 100644
--- a/usr/src/lib/libc/sparc/fp/_Q_cplx_div_rx.c
+++ b/usr/src/lib/libc/sparc/fp/_Q_cplx_div_rx.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* On SPARC V8, _Q_cplx_div_rx(v, a, w) sets *v = *a / *w with in-
* finities handling according to C99.
@@ -80,7 +78,7 @@ testinfl(long double x)
long double _Complex
_Q_cplx_div_rx(const long double *pa, const long double _Complex *w)
{
- long double _Complex v;
+ long double _Complex v = 0;
#else
void
_Q_cplx_div_rx(long double _Complex *v, const long double *pa,
diff --git a/usr/src/lib/libc/sparc/fp/_Q_cplx_lr_div.c b/usr/src/lib/libc/sparc/fp/_Q_cplx_lr_div.c
index 92473041e3..120b94f38b 100644
--- a/usr/src/lib/libc/sparc/fp/_Q_cplx_lr_div.c
+++ b/usr/src/lib/libc/sparc/fp/_Q_cplx_lr_div.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* On SPARC V8, _Q_cplx_lr_div(v, z, w) sets *v = *z / *w computed
* by the textbook formula without regard to exceptions or special
@@ -45,7 +43,7 @@
long double _Complex
_Q_cplx_lr_div(const long double _Complex *z, const long double _Complex *w)
{
- long double _Complex v;
+ long double _Complex v = 0;
#else
void
_Q_cplx_lr_div(long double _Complex *v, const long double _Complex *z,
diff --git a/usr/src/lib/libc/sparc/fp/_Q_cplx_lr_div_ix.c b/usr/src/lib/libc/sparc/fp/_Q_cplx_lr_div_ix.c
index ca968d809a..916d239159 100644
--- a/usr/src/lib/libc/sparc/fp/_Q_cplx_lr_div_ix.c
+++ b/usr/src/lib/libc/sparc/fp/_Q_cplx_lr_div_ix.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* On SPARC V8, _Q_cplx_lr_div_ix(v, b, w) sets *v = (I * *b / *w)
* compute by the textbook formula without regard to exceptions or
@@ -45,7 +43,7 @@
long double _Complex
_Q_cplx_lr_div_ix(const long double *pb, const long double _Complex *w)
{
- long double _Complex v;
+ long double _Complex v = 0;
#else
void
_Q_cplx_lr_div_ix(long double _Complex *v, const long double *pb,
diff --git a/usr/src/lib/libc/sparc/fp/_Q_cplx_lr_div_rx.c b/usr/src/lib/libc/sparc/fp/_Q_cplx_lr_div_rx.c
index b6b91ddf48..8159e10ab0 100644
--- a/usr/src/lib/libc/sparc/fp/_Q_cplx_lr_div_rx.c
+++ b/usr/src/lib/libc/sparc/fp/_Q_cplx_lr_div_rx.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* On SPARC V8, _Q_cplx_lr_div_rx(v, a, w) sets *v = *a / *w computed
* by the textbook formula without regard to exceptions or special
@@ -45,7 +43,7 @@
long double _Complex
_Q_cplx_lr_div_rx(const long double *pa, const long double _Complex *w)
{
- long double _Complex v;
+ long double _Complex v = 0;
#else
void
_Q_cplx_lr_div_rx(long double _Complex *v, const long double *pa,
diff --git a/usr/src/lib/libc/sparc/fp/_Q_cplx_lr_mul.c b/usr/src/lib/libc/sparc/fp/_Q_cplx_lr_mul.c
index f2be5888df..b52ead1ba2 100644
--- a/usr/src/lib/libc/sparc/fp/_Q_cplx_lr_mul.c
+++ b/usr/src/lib/libc/sparc/fp/_Q_cplx_lr_mul.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* On SPARC V8, _Q_cplx_lr_mul(v, z, w) sets *v = *z * *w computed by
* the textbook formula without regard to exceptions or special cases.
@@ -44,7 +42,7 @@
long double _Complex
_Q_cplx_lr_mul(const long double _Complex *z, const long double _Complex *w)
{
- long double _Complex v;
+ long double _Complex v = 0;
#else
void
_Q_cplx_lr_mul(long double _Complex *v, const long double _Complex *z,
diff --git a/usr/src/lib/libc/sparc/fp/_Q_cplx_mul.c b/usr/src/lib/libc/sparc/fp/_Q_cplx_mul.c
index 9e4d41b2f7..6afbbe6a19 100644
--- a/usr/src/lib/libc/sparc/fp/_Q_cplx_mul.c
+++ b/usr/src/lib/libc/sparc/fp/_Q_cplx_mul.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* On SPARC V8, _Q_cplx_mul(v, z, w) sets *v = *z * *w with infinities
* handled according to C99.
@@ -86,7 +84,7 @@ testinfl(long double x)
long double _Complex
_Q_cplx_mul(const long double _Complex *z, const long double _Complex *w)
{
- long double _Complex v;
+ long double _Complex v = 0;
#else
void
_Q_cplx_mul(long double _Complex *v, const long double _Complex *z,
diff --git a/usr/src/lib/libc/sparc/gen/getctxt.c b/usr/src/lib/libc/sparc/gen/getctxt.c
index 3213955108..317a3f92ec 100644
--- a/usr/src/lib/libc/sparc/gen/getctxt.c
+++ b/usr/src/lib/libc/sparc/gen/getctxt.c
@@ -25,16 +25,15 @@
*/
/* Copyright (c) 1988 AT&T */
-/* All Rights Reserved */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#pragma weak _getcontext = getcontext
+/* All Rights Reserved */
#include "lint.h"
#include "thr_uberdata.h"
#include <ucontext.h>
#include <sys/types.h>
+#include "libc.h"
+
+#pragma weak _getcontext = getcontext
int
getcontext(ucontext_t *ucp)
diff --git a/usr/src/lib/libc/sparcv9/Makefile.com b/usr/src/lib/libc/sparcv9/Makefile.com
index 7689a5b66e..42a6048ff8 100644
--- a/usr/src/lib/libc/sparcv9/Makefile.com
+++ b/usr/src/lib/libc/sparcv9/Makefile.com
@@ -1299,7 +1299,9 @@ $(ASSYMDEP_OBJS:%=pics/%): assym.h
assym.h := CFLAGS64 += $(CCGDEBUG)
GENASSYM_C = $(LIBCDIR)/$(MACH)/genassym.c
-LDFLAGS.native = $(LDASSERTS) $(ZASSERTDEFLIB)=libc.so $(BDIRECT)
+LDFLAGS.native = $(LDASSERTS) $(BDIRECT)
+
+genassym := NATIVE_LIBS += libc.so
genassym: $(GENASSYM_C)
$(NATIVECC) $(NATIVE_CFLAGS) -I$(LIBCBASE)/inc -I$(LIBCDIR)/inc \
diff --git a/usr/src/lib/libc/sparcv9/gen/getctxt.c b/usr/src/lib/libc/sparcv9/gen/getctxt.c
index 3213955108..317a3f92ec 100644
--- a/usr/src/lib/libc/sparcv9/gen/getctxt.c
+++ b/usr/src/lib/libc/sparcv9/gen/getctxt.c
@@ -25,16 +25,15 @@
*/
/* Copyright (c) 1988 AT&T */
-/* All Rights Reserved */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#pragma weak _getcontext = getcontext
+/* All Rights Reserved */
#include "lint.h"
#include "thr_uberdata.h"
#include <ucontext.h>
#include <sys/types.h>
+#include "libc.h"
+
+#pragma weak _getcontext = getcontext
int
getcontext(ucontext_t *ucp)
diff --git a/usr/src/lib/libdns_sd/Makefile.com b/usr/src/lib/libdns_sd/Makefile.com
index 44b7b6c104..6bd7b77b21 100644
--- a/usr/src/lib/libdns_sd/Makefile.com
+++ b/usr/src/lib/libdns_sd/Makefile.com
@@ -38,7 +38,7 @@ LDLIBS += -lsocket -lnsl -lc
CSTD = $(CSTD_GNU99)
CPPFLAGS += -I$(SRCDIR) -DNOT_HAVE_SA_LEN -D_XPG4_2 -D__EXTENSIONS__
-CPPFLAGS += -DMDNS_VERSIONSTR_NODTS -DmDNSResponderVersion=878.1.1
+CPPFLAGS += -DMDNS_VERSIONSTR_NODTS -DmDNSResponderVersion=1310.80.1
pics/dnssd_clientstub.o := CERRWARN += -_gcc=-Wno-unused-but-set-variable
diff --git a/usr/src/lib/libfru/libfruraw/fruraw.c b/usr/src/lib/libfru/libfruraw/fruraw.c
index 39d341486b..968a9bd053 100644
--- a/usr/src/lib/libfru/libfruraw/fruraw.c
+++ b/usr/src/lib/libfru/libfruraw/fruraw.c
@@ -549,10 +549,17 @@ frt_get_segment_name(fru_seghdl_t node, char **name)
for (each_seg = 0; each_seg < num_segment; each_seg++) {
if (segs[each_seg].handle == node) {
- segs[each_seg].name[FRU_SEGNAMELEN] = '\0';
- *name = strdup(segs[each_seg].name);
+ *name = malloc(SEG_NAME_LEN + 1);
+ if (*name != NULL) {
+ (void) memcpy(*name,
+ segs[each_seg].name,
+ SEG_NAME_LEN);
+ *name[SEG_NAME_LEN] = '\0';
+ }
free(sects);
free(segs);
+ if (*name == NULL)
+ return (FRU_FAILURE);
return (FRU_SUCCESS);
}
}
diff --git a/usr/src/lib/libfru/libfruraw/raw_access.c b/usr/src/lib/libfru/libfruraw/raw_access.c
index 7c1d2077e1..3ffca614da 100644
--- a/usr/src/lib/libfru/libfruraw/raw_access.c
+++ b/usr/src/lib/libfru/libfruraw/raw_access.c
@@ -205,7 +205,7 @@ create_packet_hash_object(void)
static hash_obj_t *
get_container_hash_object(int object_type, handle_t handle)
{
- hash_obj_t *hash_obj;
+ hash_obj_t *hash_obj = NULL;
switch (object_type) {
case CONTAINER_TYPE:
diff --git a/usr/src/lib/libsldap/common/ns_confmgr.c b/usr/src/lib/libsldap/common/ns_confmgr.c
index 862e20d035..7fa980d412 100644
--- a/usr/src/lib/libsldap/common/ns_confmgr.c
+++ b/usr/src/lib/libsldap/common/ns_confmgr.c
@@ -124,7 +124,7 @@ read_file(ns_config_t *ptr, int cred_file, ns_ldap_error_t **error)
gettext("Unable to open filename '%s' "
"for reading (errno=%d)."), file, errno);
MKERROR(LOG_ERR, *error, NS_CONFIG_FILE, strdup(errstr),
- NS_LDAP_MEMORY);
+ NS_PARSE_ERR);
return (NS_NOTFOUND);
}
@@ -150,7 +150,7 @@ read_file(ns_config_t *ptr, int cred_file, ns_ldap_error_t **error)
gettext("Missing Name or Value on line %d."),
lineno);
MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
- strdup(errstr), NS_LDAP_MEMORY);
+ strdup(errstr), NS_PARSE_ERR);
(void) fclose(fp);
return (NS_PARSE_ERR);
}
@@ -159,7 +159,7 @@ read_file(ns_config_t *ptr, int cred_file, ns_ldap_error_t **error)
gettext("Illegal profile type on line %d."),
lineno);
MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
- strdup(errstr), NS_LDAP_MEMORY);
+ strdup(errstr), NS_PARSE_ERR);
(void) fclose(fp);
return (NS_PARSE_ERR);
}
@@ -168,7 +168,7 @@ read_file(ns_config_t *ptr, int cred_file, ns_ldap_error_t **error)
gettext("Illegal NS_LDAP_FILE_VERSION "
"on line %d."), lineno);
MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
- strdup(errstr), NS_LDAP_MEMORY);
+ strdup(errstr), NS_PARSE_ERR);
(void) fclose(fp);
return (NS_PARSE_ERR);
}
@@ -188,7 +188,7 @@ read_file(ns_config_t *ptr, int cred_file, ns_ldap_error_t **error)
gettext("Illegal entry in '%s' on "
"line %d"), file, lineno);
MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
- strdup(errstr), NS_LDAP_MEMORY);
+ strdup(errstr), NS_PARSE_ERR);
(void) fclose(fp);
return (NS_PARSE_ERR);
}
@@ -208,7 +208,7 @@ read_file(ns_config_t *ptr, int cred_file, ns_ldap_error_t **error)
gettext("Illegal entry in '%s' on "
"line %d"), file, lineno);
MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX,
- strdup(errstr), NS_LDAP_MEMORY);
+ strdup(errstr), NS_PARSE_ERR);
(void) fclose(fp);
return (NS_PARSE_ERR);
}
@@ -220,7 +220,7 @@ read_file(ns_config_t *ptr, int cred_file, ns_ldap_error_t **error)
(void) snprintf(errstr, sizeof (errstr),
gettext("Empty config file: '%s'"), file);
MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX, strdup(errstr),
- NS_LDAP_MEMORY);
+ NS_PARSE_ERR);
return (NS_PARSE_ERR);
}
if (linelen == -2) {
@@ -228,7 +228,7 @@ read_file(ns_config_t *ptr, int cred_file, ns_ldap_error_t **error)
(void) snprintf(errstr, sizeof (errstr),
gettext("Line too long in '%s'"), file);
MKERROR(LOG_ERR, *error, NS_CONFIG_SYNTAX, strdup(errstr),
- NS_LDAP_MEMORY);
+ NS_PARSE_ERR);
return (NS_PARSE_ERR);
}
return (NS_SUCCESS);
@@ -237,10 +237,8 @@ read_file(ns_config_t *ptr, int cred_file, ns_ldap_error_t **error)
static
ns_ldap_return_code
-set_attr(ns_config_t *config_struct,
- char *attr_name,
- char *attr_val,
- ns_ldap_error_t **errorp)
+set_attr(ns_config_t *config_struct, char *attr_name, char *attr_val,
+ ns_ldap_error_t **errorp)
{
ParamIndexType idx;
char errmsg[MAXERROR];
@@ -471,7 +469,7 @@ __print2buf(LineBuf *line, const char *toprint, char *sep)
ns_ldap_error_t *
__ns_ldap_LoadDoorInfo(LineBuf *configinfo, char *domainname,
- ns_config_t *new, int cred_only)
+ ns_config_t *new, int cred_only)
{
ns_config_t *ptr;
char errstr[MAXERROR];
@@ -824,7 +822,7 @@ __ns_ldap_make_config(ns_ldap_result_t *result)
{
int l, m;
char val[BUFSIZE];
- char *attrname;
+ char *attrname;
ns_ldap_entry_t *entry;
ns_ldap_attr_t *attr;
char **attrval;
@@ -997,7 +995,7 @@ makeconfigerror:
*/
int
__ns_ldap_download(const char *profile, char *addr, char *baseDN,
- ns_ldap_error_t **errorp)
+ ns_ldap_error_t **errorp)
{
char filter[BUFSIZE];
int rc;
diff --git a/usr/src/lib/libsldap/common/ns_reads.c b/usr/src/lib/libsldap/common/ns_reads.c
index da987fd81a..414ddffaa1 100644
--- a/usr/src/lib/libsldap/common/ns_reads.c
+++ b/usr/src/lib/libsldap/common/ns_reads.c
@@ -2052,7 +2052,7 @@ multi_result(ns_ldap_cookie_t *cookie)
gettext(ldap_err2string(cookie->err_rc)));
err = strdup(errstr);
MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
- NS_LDAP_MEMORY);
+ LDAP_ERROR);
cookie->err_rc = NS_LDAP_INTERNAL;
cookie->errorp = *errorp;
return (LDAP_ERROR);
@@ -2122,7 +2122,7 @@ multi_result(ns_ldap_cookie_t *cookie)
gettext(ldap_err2string(cookie->err_rc)));
err = strdup(errstr);
MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
- NS_LDAP_MEMORY);
+ LDAP_ERROR);
cookie->err_rc = NS_LDAP_INTERNAL;
cookie->errorp = *errorp;
return (LDAP_ERROR);
@@ -2380,7 +2380,7 @@ search_state_machine(ns_ldap_cookie_t *cookie, ns_state_t state, int cycle)
state);
err = strdup(errstr);
MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
- NS_LDAP_MEMORY);
+ LDAP_ERROR);
cookie->err_rc = NS_LDAP_INTERNAL;
cookie->errorp = *errorp;
cookie->new_state = EXIT;
@@ -2922,15 +2922,15 @@ search_state_machine(ns_ldap_cookie_t *cookie, ns_state_t state, int cycle)
if (cookie->err_rc == LDAP_SERVER_DOWN) {
MKERROR(LOG_INFO, *errorp,
cookie->err_rc, err,
- NS_LDAP_MEMORY);
+ LDAP_ERROR);
} else {
MKERROR(LOG_WARNING, *errorp,
cookie->err_rc, err,
- NS_LDAP_MEMORY);
+ LDAP_ERROR);
}
} else {
MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL,
- err, NS_LDAP_MEMORY);
+ err, LDAP_ERROR);
}
cookie->err_rc = NS_LDAP_INTERNAL;
cookie->errorp = *errorp;
@@ -2954,7 +2954,7 @@ search_state_machine(ns_ldap_cookie_t *cookie, ns_state_t state, int cycle)
cookie->state);
err = strdup(errstr);
MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
- NS_LDAP_MEMORY);
+ LDAP_ERROR);
cookie->err_rc = NS_LDAP_INTERNAL;
cookie->errorp = *errorp;
return (ERROR);
diff --git a/usr/src/lib/nsswitch/ldap/common/getexecattr.c b/usr/src/lib/nsswitch/ldap/common/getexecattr.c
index abd22908e0..fc44698267 100644
--- a/usr/src/lib/nsswitch/ldap/common/getexecattr.c
+++ b/usr/src/lib/nsswitch/ldap/common/getexecattr.c
@@ -21,6 +21,7 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2021 Joyent, Inc.
*/
#include <secdb.h>
@@ -355,7 +356,7 @@ result_exec2str:
static nss_status_t
_exec_process_val(ldap_backend_ptr be, nss_XbyY_args_t *argp)
{
- int status;
+ int status;
nss_status_t nss_stat = NSS_UNAVAIL;
ns_ldap_attr_t *attrptr;
ns_ldap_entry_t *entry;
@@ -420,7 +421,7 @@ get_wild(ldap_backend_ptr be, nss_XbyY_args_t *argp, int getby_flag)
const char *policy = _priv_exec->policy;
const char *type = _priv_exec->type;
- if (strpbrk(policy, "*()\\") != NULL ||
+ if ((policy != NULL && strpbrk(policy, "*()\\") != NULL) ||
type != NULL && strpbrk(type, "*()\\") != NULL)
return ((nss_status_t)NSS_NOTFOUND);
@@ -446,11 +447,12 @@ get_wild(ldap_backend_ptr be, nss_XbyY_args_t *argp, int getby_flag)
switch (getby_flag) {
case NSS_DBOP_EXECATTR_BYID:
ret = snprintf(searchfilter, sizeof (searchfilter),
- _EXEC_GETEXECID, id, policy, ISWILD(type));
+ _EXEC_GETEXECID, id, ISWILD(policy), ISWILD(type));
if (ret >= sizeof (searchfilter) || ret < 0)
goto go_out;
ret = snprintf(userdata, sizeof (userdata),
- _EXEC_GETEXECID_SSD, id, policy, ISWILD(type));
+ _EXEC_GETEXECID_SSD, id, ISWILD(policy),
+ ISWILD(type));
if (ret >= sizeof (userdata) || ret < 0)
goto go_out;
break;
@@ -458,12 +460,12 @@ get_wild(ldap_backend_ptr be, nss_XbyY_args_t *argp, int getby_flag)
case NSS_DBOP_EXECATTR_BYNAMEID:
ret = snprintf(searchfilter, sizeof (searchfilter),
_EXEC_GETEXECNAMEID, name, id,
- policy, ISWILD(type));
+ ISWILD(policy), ISWILD(type));
if (ret >= sizeof (searchfilter) || ret < 0)
goto go_out;
ret = snprintf(userdata, sizeof (userdata),
_EXEC_GETEXECNAMEID_SSD, name, id,
- policy, ISWILD(type));
+ ISWILD(policy), ISWILD(type));
if (ret >= sizeof (userdata) || ret < 0)
goto go_out;
break;
@@ -484,8 +486,8 @@ go_out:
}
static nss_status_t
-exec_attr_process_val(ldap_backend_ptr be, nss_XbyY_args_t *argp) {
-
+exec_attr_process_val(ldap_backend_ptr be, nss_XbyY_args_t *argp)
+{
_priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp);
int stat, nss_stat = NSS_SUCCESS;
@@ -497,10 +499,10 @@ exec_attr_process_val(ldap_backend_ptr be, nss_XbyY_args_t *argp) {
if (argp->buf.result != NULL) {
/* file format -> execstr_t */
stat = (*argp->str2ent)(be->buffer,
- be->buflen,
- argp->buf.result,
- argp->buf.buffer,
- argp->buf.buflen);
+ be->buflen,
+ argp->buf.result,
+ argp->buf.buffer,
+ argp->buf.buflen);
if (stat == NSS_STR_PARSE_SUCCESS) {
argp->returnval = argp->buf.result;
argp->returnlen = 1; /* irrelevant */
@@ -544,16 +546,16 @@ getbynam(ldap_backend_ptr be, void *a)
const char *policy = _priv_exec->policy;
const char *type = _priv_exec->type;
- if (strpbrk(policy, "*()\\") != NULL ||
+ if (policy != NULL && strpbrk(policy, "*()\\") != NULL ||
type != NULL && strpbrk(type, "*()\\") != NULL ||
_ldap_filter_name(name, _priv_exec->name, sizeof (name)) != 0)
return ((nss_status_t)NSS_NOTFOUND);
ret = snprintf(searchfilter, sizeof (searchfilter),
- _EXEC_GETEXECNAME, name, policy, ISWILD(type));
+ _EXEC_GETEXECNAME, name, ISWILD(policy), ISWILD(type));
if (ret >= sizeof (searchfilter) || ret < 0)
return ((nss_status_t)NSS_NOTFOUND);
ret = snprintf(userdata, sizeof (userdata),
- _EXEC_GETEXECNAME_SSD, name, policy, ISWILD(type));
+ _EXEC_GETEXECNAME_SSD, name, ISWILD(policy), ISWILD(type));
if (ret >= sizeof (userdata) || ret < 0)
return ((nss_status_t)NSS_NOTFOUND);
diff --git a/usr/src/lib/sun_sas/common/Sun_sasFreeLibrary.c b/usr/src/lib/sun_sas/common/Sun_sasFreeLibrary.c
index b30e975fe1..78b2100e89 100644
--- a/usr/src/lib/sun_sas/common/Sun_sasFreeLibrary.c
+++ b/usr/src/lib/sun_sas/common/Sun_sasFreeLibrary.c
@@ -48,6 +48,7 @@ Sun_sasFreeLibrary(void)
open_handle_index = 1;
unlock(&all_hbas_lock);
(void) mutex_destroy(&all_hbas_lock);
+ (void) mutex_destroy(&open_handles_lock);
/* free sysevent handle. */
if (gSysEventHandle != NULL)
diff --git a/usr/src/lib/sun_sas/common/Sun_sasLoadLibrary.c b/usr/src/lib/sun_sas/common/Sun_sasLoadLibrary.c
index b5df2a4cc8..45164c5058 100644
--- a/usr/src/lib/sun_sas/common/Sun_sasLoadLibrary.c
+++ b/usr/src/lib/sun_sas/common/Sun_sasLoadLibrary.c
@@ -27,6 +27,11 @@
#include <sun_sas.h>
+mutex_t all_hbas_lock = DEFAULTMUTEX;
+mutex_t open_handles_lock = DEFAULTMUTEX;
+HBA_UINT16 open_handle_index;
+HBA_UINT32 hba_count;
+
/*
* Loads the HBA Library. Must be called before calling any HBA library
* functions
@@ -53,23 +58,17 @@ HBA_STATUS Sun_sasLoadLibrary() {
}
hba_count = 0;
open_handle_index = 1;
- /* Initialize the read-write lock */
- if (mutex_init(&all_hbas_lock, USYNC_THREAD, NULL)) {
- log(LOG_DEBUG, ROUTINE,
- "Unable to initialize lock in LoadLibrary for reason \"%s\"",
- strerror(errno));
- return (HBA_STATUS_ERROR);
- }
+
/* grab write lock */
lock(&all_hbas_lock);
start = gethrtime();
if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
- log(LOG_DEBUG, ROUTINE,
- "Unable to load device tree for reason \"%s\"",
- strerror(errno));
- unlock(&all_hbas_lock);
- return (HBA_STATUS_ERROR);
+ log(LOG_DEBUG, ROUTINE,
+ "Unable to load device tree: \"%s\"",
+ strerror(errno));
+ unlock(&all_hbas_lock);
+ return (HBA_STATUS_ERROR);
}
end = gethrtime();
duration = end - start;
@@ -79,9 +78,9 @@ HBA_STATUS Sun_sasLoadLibrary() {
/* At load time, we only gather libdevinfo information */
if (devtree_get_all_hbas(root) == HBA_STATUS_OK) {
- atLeastOneHBA = B_TRUE;
+ atLeastOneHBA = B_TRUE;
} else {
- atLeastOneFailure = B_TRUE;
+ atLeastOneFailure = B_TRUE;
}
di_fini(root);
@@ -90,13 +89,14 @@ HBA_STATUS Sun_sasLoadLibrary() {
/* Now determine what status code to return */
if (atLeastOneHBA) {
- /* We've got at least one HBA and possibly some failures */
- return (HBA_STATUS_OK);
- } else if (atLeastOneFailure) {
- /* We have no HBAs but have failures */
- return (HBA_STATUS_ERROR);
- } else {
- /* We have no HBAs and no failures */
- return (HBA_STATUS_OK);
+ /* We've got at least one HBA and possibly some failures */
+ return (HBA_STATUS_OK);
+ }
+ if (atLeastOneFailure) {
+ /* We have no HBAs but have failures */
+ return (HBA_STATUS_ERROR);
}
+
+ /* We have no HBAs and no failures */
+ return (HBA_STATUS_OK);
}
diff --git a/usr/src/lib/sun_sas/common/devtree_hba_disco.c b/usr/src/lib/sun_sas/common/devtree_hba_disco.c
index bfd584008b..2017f97e26 100644
--- a/usr/src/lib/sun_sas/common/devtree_hba_disco.c
+++ b/usr/src/lib/sun_sas/common/devtree_hba_disco.c
@@ -33,6 +33,8 @@
#include <inttypes.h>
#include <ctype.h>
+struct sun_sas_hba *global_hba_head;
+
/* free hba port info for the given hba */
static void
free_hba_port(struct sun_sas_hba *hba_ptr)
diff --git a/usr/src/lib/sun_sas/common/sun_sas.h b/usr/src/lib/sun_sas/common/sun_sas.h
index d6872e5628..75344e6de3 100644
--- a/usr/src/lib/sun_sas/common/sun_sas.h
+++ b/usr/src/lib/sun_sas/common/sun_sas.h
@@ -107,11 +107,11 @@ extern "C" {
/* misc */
#define SUN_MICROSYSTEMS "Sun Microsystems, Inc."
-mutex_t all_hbas_lock;
-mutex_t open_handles_lock;
-mutex_t log_file_lock;
-HBA_UINT32 hba_count;
-HBA_UINT16 open_handle_index;
+extern mutex_t all_hbas_lock;
+extern mutex_t open_handles_lock;
+extern mutex_t log_file_lock;
+extern HBA_UINT32 hba_count;
+extern HBA_UINT16 open_handle_index;
/* Internal structures that aren't exposed to clients */
@@ -136,7 +136,7 @@ struct sun_sas_hba {
struct sun_sas_port *first_port;
};
-struct sun_sas_hba *global_hba_head;
+extern struct sun_sas_hba *global_hba_head;
struct ScsiEntryList {
SMHBA_SCSIENTRY entry;
diff --git a/usr/src/man/man1m/nvmeadm.1m b/usr/src/man/man1m/nvmeadm.1m
index feb699dd79..32620b6747 100644
--- a/usr/src/man/man1m/nvmeadm.1m
+++ b/usr/src/man/man1m/nvmeadm.1m
@@ -11,8 +11,9 @@
.\"
.\" Copyright 2016 Nexenta Systems, Inc. All rights reserved.
.\" Copyright 2019 Western Digital Corporation.
+.\" Copyright 2021 Oxide Computer Company
.\"
-.Dd June 27, 2019
+.Dd March 24, 2021
.Dt NVMEADM 1M
.Os
.Sh NAME
@@ -25,20 +26,24 @@
.Nm
.Op Fl dv
.Cm list
-.Op Ar ctl[/ns][,...]
+.Oo
+.Fl p
+.Fl o Ar field Ns [,...]
+.Oc
+.Op Ar ctl[/ns] Ns [,...]
.Nm
.Op Fl dv
.Cm identify
-.Ar ctl[/ns][,...]
+.Ar ctl[/ns] Ns [,...]
.Nm
.Op Fl dv
.Cm get-logpage
-.Ar ctl[/ns][,...]
+.Ar ctl[/ns] Ns [,...]
.Ar logpage
.Nm
.Op Fl dv
.Cm get-features
-.Ar ctl[/ns][,...]
+.Ar ctl[/ns] Ns [,...]
.Op Ar feature-list
.Nm
.Op Fl dv
@@ -180,16 +185,68 @@ logpage.
.It Xo
.Nm
.Cm list
-.Op Ar ctl[/ns][,...]
+.Oo
+.Fl p
+.Fl o Ar field Ns [,...]
+.Oc
+.Op Ar ctl[/ns] Ns [,...]
.Xc
Lists the NVMe controllers and their namespaces in the system and
prints a 1-line summary of their basic properties for each.
If a list of controllers and/or namespaces is given then the listing
is limited to those devices.
+By default, output is human-readable; however, a parsable form can
+controlled by using the following options:
+.Bl -tag -width Fl
+.It Fl p
+Rather than printing human-readable output, outputs an entry for each of
+the specified controllers and namespaces.
+If no controllers or namespaces are given as arguments, then the primary
+namespace of each controller is listed and if the
+.Fl v
+option is specified, then all of the namespaces for a controller are
+listed.
+This option requires that output fields be selected with the
+.Fl o
+option.
+.It Fl o Ar field Ns [,...]
+A comma-separated list of one or more output fields to be used.
+Fields are listed below and the name is case insensitive.
+.El
+.Pp
+The following fields can be specified when using the parsable form:
+.Bl -tag -width CAPACITY
+.It Sy MODEL
+The model number of the device, generally containing information about
+both the manufacturer and the product.
+.It Sy SERIAL
+The NVMe controller's serial number.
+.It Sy FWREV
+The controller's firmware revision.
+.It Sy VERSION
+The version of the NVMe specification the controller supports.
+.It Sy SIZE
+The logical size in bytes of the namespace.
+.It Sy CAPACITY
+The amount of logical bytes that the namespace may actually have allocated at
+any time.
+This may be different than size due to the use of thin provisioning or due to
+administrative action.
+.It Sy USED
+The number of bytes used in the namespace.
+.It Sy INSTANCE
+The name of the device node and instance of it.
+.It Sy NAMESPACE
+The numerical value of the namespace which can be used as part of other
+.Nm
+operations.
+.It Sy DISK
+The name of the disk device that corresponds to the namespace, if any.
+.El
.It Xo
.Nm
.Cm identify
-.Ar ctl[/ns][,...]
+.Ar ctl[/ns] Ns [,...]
.Xc
Print detailed information about the specified controllers and/or
namespaces.
@@ -202,7 +259,7 @@ admin command in the NVMe specification.
.It Xo
.Nm
.Cm get-logpage
-.Ar ctl[/ns][,...]
+.Ar ctl[/ns] Ns [,...]
.Ar logpage
.Xc
Print the specified log page of the specified controllers and/or namespaces.
@@ -225,7 +282,7 @@ admin command in the NVMe specification.
.It Xo
.Nm
.Cm get-features
-.Ar ctl[/ns][,...]
+.Ar ctl[/ns] Ns [,...]
.Op Ar feature-list
.Xc
Prints information about the specified features, or all features if
diff --git a/usr/src/pkg/manifests/diagnostic-pci.mf b/usr/src/pkg/manifests/diagnostic-pci.mf
index c666862ebd..a2a1610726 100644
--- a/usr/src/pkg/manifests/diagnostic-pci.mf
+++ b/usr/src/pkg/manifests/diagnostic-pci.mf
@@ -23,4 +23,5 @@ dir path=usr group=sys
dir path=usr/lib
dir path=usr/lib/pci
file path=usr/lib/pci/pcidb mode=0555
+file path=usr/lib/pci/pcieadm mode=0555
license lic_CDDL license=lic_CDDL
diff --git a/usr/src/pkg/manifests/system-test-utiltest.mf b/usr/src/pkg/manifests/system-test-utiltest.mf
index 963821dff2..914154281f 100644
--- a/usr/src/pkg/manifests/system-test-utiltest.mf
+++ b/usr/src/pkg/manifests/system-test-utiltest.mf
@@ -77,6 +77,7 @@ dir path=opt/util-tests/tests/mdb/format
dir path=opt/util-tests/tests/mdb/options
dir path=opt/util-tests/tests/mdb/typedef
dir path=opt/util-tests/tests/mergeq
+dir path=opt/util-tests/tests/pci
dir path=opt/util-tests/tests/sed
dir path=opt/util-tests/tests/sed/regress.multitest.out
dir path=opt/util-tests/tests/sleep
@@ -1686,7 +1687,23 @@ file path=opt/util-tests/tests/mdb/typedef/tst.union.mdb mode=0444
file path=opt/util-tests/tests/mdb/typedef/tst.union.mdb.out mode=0444
file path=opt/util-tests/tests/mergeq/mqt mode=0555
file path=opt/util-tests/tests/mergeq/wqt mode=0555
+file path=opt/util-tests/tests/pci/bridge-efilt-p.out mode=0444
+file path=opt/util-tests/tests/pci/bridge-efilt.out mode=0444
+file path=opt/util-tests/tests/pci/bridge-ht-p.out mode=0444
+file path=opt/util-tests/tests/pci/bridge-ht.msi-p.out mode=0444
+file path=opt/util-tests/tests/pci/bridge-ht.msi.command-p.out mode=0444
+file path=opt/util-tests/tests/pci/bridge-ht.out mode=0444
+file path=opt/util-tests/tests/pci/bridge.pci mode=0444
+file path=opt/util-tests/tests/pci/header0-basic-L.out mode=0444
+file path=opt/util-tests/tests/pci/header0-basic-LH.out mode=0444
+file path=opt/util-tests/tests/pci/header0-basic-n.out mode=0444
+file path=opt/util-tests/tests/pci/header0-basic.out mode=0444
+file path=opt/util-tests/tests/pci/header0-parse.out mode=0444
+file path=opt/util-tests/tests/pci/igb-ltr-p.out mode=0444
+file path=opt/util-tests/tests/pci/igb-ltr.out mode=0444
+file path=opt/util-tests/tests/pci/igb.pci mode=0444
file path=opt/util-tests/tests/pcidbtest mode=0555
+file path=opt/util-tests/tests/pcieadmtest mode=0555
file path=opt/util-tests/tests/printf_test mode=0555
file path=opt/util-tests/tests/sed/multi_test mode=0555
file path=opt/util-tests/tests/sed/regress.multitest.out/1.1 mode=0444
diff --git a/usr/src/test/util-tests/runfiles/default.run b/usr/src/test/util-tests/runfiles/default.run
index c4ea9ed8e1..9b8ba57fbf 100644
--- a/usr/src/test/util-tests/runfiles/default.run
+++ b/usr/src/test/util-tests/runfiles/default.run
@@ -88,3 +88,4 @@ tests = ['custr_remove', 'custr_trunc']
tests = ['sed_addr', 'multi_test']
[/opt/util-tests/tests/pcidbtest]
+[/opt/util-tests/tests/pcieadmtest]
diff --git a/usr/src/test/util-tests/tests/Makefile b/usr/src/test/util-tests/tests/Makefile
index 77a20d6059..1d73f5dc94 100644
--- a/usr/src/test/util-tests/tests/Makefile
+++ b/usr/src/test/util-tests/tests/Makefile
@@ -20,6 +20,6 @@
SUBDIRS = date dis dladm iconv libnvpair_json libsff printf xargs grep_xpg4
SUBDIRS += demangle mergeq workq chown ctf smbios libjedec awk make sleep
-SUBDIRS += bunyan libcustr find mdb sed head pcidb
+SUBDIRS += bunyan libcustr find mdb sed head pcidb pcieadm
include $(SRC)/test/Makefile.com
diff --git a/usr/src/test/util-tests/tests/pcieadm/Makefile b/usr/src/test/util-tests/tests/pcieadm/Makefile
new file mode 100644
index 0000000000..59a995f0ea
--- /dev/null
+++ b/usr/src/test/util-tests/tests/pcieadm/Makefile
@@ -0,0 +1,59 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2021 Oxide Computer Company
+#
+
+include $(SRC)/cmd/Makefile.cmd
+include $(SRC)/test/Makefile.com
+
+ROOTOPTPKG = $(ROOT)/opt/util-tests/tests
+ROOTOPTPCI = $(ROOT)/opt/util-tests/tests/pci
+PROG = pcieadmtest
+DATAFILES = bridge.pci igb.pci \
+ header0-basic.out \
+ header0-basic-L.out \
+ header0-basic-LH.out \
+ header0-basic-n.out \
+ header0-parse.out \
+ igb-ltr.out \
+ igb-ltr-p.out \
+ bridge-ht.out \
+ bridge-ht-p.out \
+ bridge-ht.msi-p.out \
+ bridge-ht.msi.command-p.out \
+ bridge-efilt.out \
+ bridge-efilt-p.out
+
+ROOTPROG = $(PROG:%=$(ROOTOPTPKG)/%)
+ROOTDATA = $(DATAFILES:%=$(ROOTOPTPCI)/%)
+$(ROOTDATA) := FILEMODE = 0444
+
+all:
+
+install: $(ROOTDATA) $(ROOTPROG)
+
+clobber: clean
+
+clean:
+
+$(ROOTOPTPKG):
+ $(INS.dir)
+
+$(ROOTOPTPCI): $(ROOTOPTPKG)
+ $(INS.dir)
+
+$(ROOTOPTPCI)/%: % $(ROOTOPTPCI)
+ $(INS.file)
+
+$(ROOTOPTPKG)/%: %.ksh $(ROOTOPTPKG)
+ $(INS.rename)
diff --git a/usr/src/test/util-tests/tests/pcieadm/bridge-efilt-p.out b/usr/src/test/util-tests/tests/pcieadm/bridge-efilt-p.out
new file mode 100644
index 0000000000..63e630294d
--- /dev/null
+++ b/usr/src/test/util-tests/tests/pcieadm/bridge-efilt-p.out
@@ -0,0 +1,2 @@
+pcie.linksts:0x7043
+pcieadm: filter 'atelier' did not match any fields
diff --git a/usr/src/test/util-tests/tests/pcieadm/bridge-efilt.out b/usr/src/test/util-tests/tests/pcieadm/bridge-efilt.out
new file mode 100644
index 0000000000..f3b2bf7680
--- /dev/null
+++ b/usr/src/test/util-tests/tests/pcieadm/bridge-efilt.out
@@ -0,0 +1,10 @@
+pcieadm: filter 'atelier' did not match any fields
+PCI Express Capability (0x10)
+ Link Status: 0x7043
+ |--> Link Speed: 8.0 GT/s (0x3)
+ |--> Link Width: 0x4
+ |--> Link Training: no (0x0)
+ |--> Slot Clock Configuration: common (0x1000)
+ |--> Data Link Layer Link Active: yes (0x2000)
+ |--> Link Bandwidth Management Status: change occurred (0x4000)
+ |--> Link Autonomous Bandwidth Status: no change (0x0)
diff --git a/usr/src/test/util-tests/tests/pcieadm/bridge-ht-p.out b/usr/src/test/util-tests/tests/pcieadm/bridge-ht-p.out
new file mode 100644
index 0000000000..09ead24746
--- /dev/null
+++ b/usr/src/test/util-tests/tests/pcieadm/bridge-ht-p.out
@@ -0,0 +1 @@
+pcieadm: filter 'ht' did not match any fields
diff --git a/usr/src/test/util-tests/tests/pcieadm/bridge-ht.msi-p.out b/usr/src/test/util-tests/tests/pcieadm/bridge-ht.msi-p.out
new file mode 100644
index 0000000000..2cd1fe59bf
--- /dev/null
+++ b/usr/src/test/util-tests/tests/pcieadm/bridge-ht.msi-p.out
@@ -0,0 +1 @@
+pcieadm: filter 'ht.msi' did not match any fields
diff --git a/usr/src/test/util-tests/tests/pcieadm/bridge-ht.msi.command-p.out b/usr/src/test/util-tests/tests/pcieadm/bridge-ht.msi.command-p.out
new file mode 100644
index 0000000000..095e12d8a1
--- /dev/null
+++ b/usr/src/test/util-tests/tests/pcieadm/bridge-ht.msi.command-p.out
@@ -0,0 +1 @@
+0xa803:ht.msi.command
diff --git a/usr/src/test/util-tests/tests/pcieadm/bridge-ht.out b/usr/src/test/util-tests/tests/pcieadm/bridge-ht.out
new file mode 100644
index 0000000000..ba2899a347
--- /dev/null
+++ b/usr/src/test/util-tests/tests/pcieadm/bridge-ht.out
@@ -0,0 +1,4 @@
+HyperTransport Capability - MSI Mapping (0x8)
+ Command: 0xa803
+ |--> Enable: enabled (0x1)
+ |--> Fixed: enabled (0x2)
diff --git a/usr/src/test/util-tests/tests/pcieadm/bridge.pci b/usr/src/test/util-tests/tests/pcieadm/bridge.pci
new file mode 100644
index 0000000000..f85ffa4f6e
--- /dev/null
+++ b/usr/src/test/util-tests/tests/pcieadm/bridge.pci
Binary files differ
diff --git a/usr/src/test/util-tests/tests/pcieadm/header0-basic-L.out b/usr/src/test/util-tests/tests/pcieadm/header0-basic-L.out
new file mode 100644
index 0000000000..c52c00d5cc
--- /dev/null
+++ b/usr/src/test/util-tests/tests/pcieadm/header0-basic-L.out
@@ -0,0 +1,3 @@
+SHORT HUMAN
+header0.vendor Vendor ID
+header0.device Device ID
diff --git a/usr/src/test/util-tests/tests/pcieadm/header0-basic-LH.out b/usr/src/test/util-tests/tests/pcieadm/header0-basic-LH.out
new file mode 100644
index 0000000000..5dda4c444b
--- /dev/null
+++ b/usr/src/test/util-tests/tests/pcieadm/header0-basic-LH.out
@@ -0,0 +1,2 @@
+header0.vendor Vendor ID
+header0.device Device ID
diff --git a/usr/src/test/util-tests/tests/pcieadm/header0-basic-n.out b/usr/src/test/util-tests/tests/pcieadm/header0-basic-n.out
new file mode 100644
index 0000000000..874bb0db55
--- /dev/null
+++ b/usr/src/test/util-tests/tests/pcieadm/header0-basic-n.out
@@ -0,0 +1,3 @@
+Device /dev/stdin -- Type 0 Header (header0)
+ Vendor ID (header0.vendor): 0x8086 -- Intel Corporation
+ Device ID (header0.device): 0x1521 -- I350 Gigabit Network Connection
diff --git a/usr/src/test/util-tests/tests/pcieadm/header0-basic.out b/usr/src/test/util-tests/tests/pcieadm/header0-basic.out
new file mode 100644
index 0000000000..93e067f828
--- /dev/null
+++ b/usr/src/test/util-tests/tests/pcieadm/header0-basic.out
@@ -0,0 +1,3 @@
+Device /dev/stdin -- Type 0 Header
+ Vendor ID: 0x8086 -- Intel Corporation
+ Device ID: 0x1521 -- I350 Gigabit Network Connection
diff --git a/usr/src/test/util-tests/tests/pcieadm/header0-parse.out b/usr/src/test/util-tests/tests/pcieadm/header0-parse.out
new file mode 100644
index 0000000000..d56cf26062
--- /dev/null
+++ b/usr/src/test/util-tests/tests/pcieadm/header0-parse.out
@@ -0,0 +1,2 @@
+header0.vendor:0x8086
+header0.device:0x1521
diff --git a/usr/src/test/util-tests/tests/pcieadm/igb-ltr-p.out b/usr/src/test/util-tests/tests/pcieadm/igb-ltr-p.out
new file mode 100644
index 0000000000..c6a9d1bce0
--- /dev/null
+++ b/usr/src/test/util-tests/tests/pcieadm/igb-ltr-p.out
@@ -0,0 +1 @@
+pcieadm: filter 'ltr' did not match any fields
diff --git a/usr/src/test/util-tests/tests/pcieadm/igb-ltr.out b/usr/src/test/util-tests/tests/pcieadm/igb-ltr.out
new file mode 100644
index 0000000000..f6a4f26cbd
--- /dev/null
+++ b/usr/src/test/util-tests/tests/pcieadm/igb-ltr.out
@@ -0,0 +1,11 @@
+Latency Tolerance Reporting Capability (0x18)
+ Capability Header: 0x1d010018
+ |--> Capability ID: 0x18
+ |--> Capability Version: 0x1
+ |--> Next Capability Offset: 0x1d0
+ Max Snoop Latency: 0x0
+ |--> Latency Value: 0x0
+ |--> Latency Scale: 1 ns (0x0)
+ Max No-Snoop Latency: 0x0
+ |--> Latency Value: 0x0
+ |--> Latency Scale: 1 ns (0x0)
diff --git a/usr/src/test/util-tests/tests/pcieadm/igb.pci b/usr/src/test/util-tests/tests/pcieadm/igb.pci
new file mode 100644
index 0000000000..bcee63f32d
--- /dev/null
+++ b/usr/src/test/util-tests/tests/pcieadm/igb.pci
Binary files differ
diff --git a/usr/src/test/util-tests/tests/pcieadm/pcieadmtest.ksh b/usr/src/test/util-tests/tests/pcieadm/pcieadmtest.ksh
new file mode 100644
index 0000000000..d68cf0b7cc
--- /dev/null
+++ b/usr/src/test/util-tests/tests/pcieadm/pcieadmtest.ksh
@@ -0,0 +1,160 @@
+#!/usr/bin/ksh
+#
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2021 Oxide Computer Company
+#
+
+unalias -a
+set -o pipefail
+
+pcieadm_arg0="$(basename $0)"
+pcieadm_prog="/usr/lib/pci/pcieadm"
+pcieadm_data="$(dirname $0)/pci"
+pcieadm_exit=0
+pcieadm_tmpfile="/tmp/pcieadmtest.$$"
+
+warn()
+{
+ typeset msg="$*"
+ [[ -z "$msg" ]] && msg="failed"
+ echo "TEST FAILED: $pcieadm_arg0: $msg" >&2
+ pcieadm_exit=1
+}
+
+pcieadm_bad_args()
+{
+ if $pcieadm_prog $@ 2>/dev/null 1>/dev/null; then
+ warn "should have failed with args "$@", but passed"
+ return
+ fi
+
+ printf "TEST PASSED: invalid arguments %s\n" "$*"
+}
+
+pcieadm_validate_output()
+{
+ typeset input="$pcieadm_data/$1"
+ shift
+ typeset outfile="$pcieadm_data/$1"
+ shift
+ typeset expexit=$1
+ shift
+
+ $pcieadm_prog $@ <$input >"$pcieadm_tmpfile" 2>&1
+ if (( $? != expexit)); then
+ warn "$@: mismatched exit status, found $?, expected $expexit"
+ fi
+
+ if ! diff $outfile $pcieadm_tmpfile; then
+ warn "$@: output mismatched"
+ else
+ printf "TEST PASSED: %s\n" "$*"
+ fi
+}
+
+
+if [[ -n $PCIEADM ]]; then
+ pcieadm_prog=$PCIEADM
+fi
+
+#
+# Before we begin execution, set up the environment such that we have a
+# standard locale and that umem will help us catch mistakes.
+#
+export LC_ALL=C.UTF-8
+export LD_PRELOAD=libumem.so
+export UMEM_DEBUG=default
+
+if [[ ! -d $pcieadm_data ]]; then
+ printf "failed to find data directory %s\n" "$pcieadm_data" >&2
+ exit 1
+fi
+
+#
+# First work through bad options.
+#
+pcieadm_bad_args
+pcieadm_bad_args -d
+pcieadm_bad_args foobar
+pcieadm_bad_args save-cfgspace
+pcieadm_bad_args save-cfgspace -a
+pcieadm_bad_args save-cfgspace -d
+pcieadm_bad_args save-cfgspace -d final
+pcieadm_bad_args save-cfgspace -a -d fantasy
+pcieadm_bad_args show-devs -h
+pcieadm_bad_args show-devs -p
+pcieadm_bad_args show-devs -s -o
+pcieadm_bad_args show-cfgspace
+pcieadm_bad_args show-cfgspace -d -H
+pcieadm_bad_args show-cfgspace -d
+pcieadm_bad_args show-cfgspace -f
+pcieadm_bad_args show-cfgspace -h
+pcieadm_bad_args show-cfgspace -L
+pcieadm_bad_args show-cfgspace -L -n -f "$pcieadm_data/igb.pci"
+pcieadm_bad_args show-cfgspace -L -p -f "$pcieadm_data/igb.pci"
+pcieadm_bad_args show-cfgspace -p -f "$pcieadm_data/igb.pci"
+pcieadm_bad_args show-cfgspace -o foo -f "$pcieadm_data/igb.pci"
+pcieadm_bad_args show-cfgspace -L -o foo -f "$pcieadm_data/igb.pci"
+
+#
+# Test different output cases
+#
+pcieadm_validate_output igb.pci header0-basic.out 0 \
+ show-cfgspace -f /dev/stdin header0.vendor header0.device
+pcieadm_validate_output igb.pci header0-basic-L.out 0 \
+ show-cfgspace -L -f /dev/stdin header0.vendor header0.device
+pcieadm_validate_output igb.pci header0-basic-n.out 0 \
+ show-cfgspace -n -f /dev/stdin header0.vendor header0.device
+pcieadm_validate_output igb.pci header0-basic-LH.out 0 \
+ show-cfgspace -L -H -f /dev/stdin header0.vendor header0.device
+
+#
+# Specific filter behavior. We want to validate the following:
+#
+# o An inexact filter (e.g. a cap or subcap) matches in human mode,
+# but not parsable.
+# o An exact filter will show its contents in human mode, but not
+# parsable.
+# o A missing filter causes to exit non-zero, but still show what we
+# found with other filters or because of a prefix match.
+#
+pcieadm_validate_output igb.pci igb-ltr.out 0 \
+ show-cfgspace -f /dev/stdin ltr
+pcieadm_validate_output igb.pci igb-ltr-p.out 1 \
+ show-cfgspace -p -o short,value -f /dev/stdin ltr
+pcieadm_validate_output igb.pci header0-parse.out 0 \
+ show-cfgspace -p -o short,value -f /dev/stdin header0.vendor header0.device
+pcieadm_validate_output bridge.pci bridge-ht.out 0 \
+ show-cfgspace -f /dev/stdin ht
+pcieadm_validate_output bridge.pci bridge-ht.out 0 \
+ show-cfgspace -f /dev/stdin ht.msi
+pcieadm_validate_output bridge.pci bridge-ht.out 0 \
+ show-cfgspace -f /dev/stdin ht.msi.command
+pcieadm_validate_output bridge.pci bridge-ht-p.out 1 \
+ show-cfgspace -p -o value,short -f /dev/stdin ht
+pcieadm_validate_output bridge.pci bridge-ht.msi-p.out 1 \
+ show-cfgspace -p -o value,short -f /dev/stdin ht.msi
+pcieadm_validate_output bridge.pci bridge-ht.msi.command-p.out 0 \
+ show-cfgspace -p -o value,short -f /dev/stdin ht.msi.command
+pcieadm_validate_output bridge.pci bridge-efilt.out 1 \
+ show-cfgspace -f /dev/stdin pcie.linksts atelier
+pcieadm_validate_output bridge.pci bridge-efilt-p.out 1 \
+ show-cfgspace -p -o short,value -f /dev/stdin pcie.linksts atelier
+
+if (( pcieadm_exit == 0 )); then
+ printf "All tests passed successfully!\n"
+fi
+
+rm -f "$pcieadm_tmpfile"
+exit $pcieadm_exit
diff --git a/usr/src/tools/Makefile.tools b/usr/src/tools/Makefile.tools
index 9fd747751d..315a10b6c6 100644
--- a/usr/src/tools/Makefile.tools
+++ b/usr/src/tools/Makefile.tools
@@ -55,9 +55,10 @@ ELFSIGN_O= $(TRUE)
LDLIBS=
LDFLAGS= $(MAPFILE.NES:%=-Wl,-M%) $(MAPFILE.NED:%=-Wl,-M%) \
$(MAPFILE.PGA:%=-Wl,-M%) \
- $(ZASSERTDEFLIB)=libc.so \
$(BDIRECT)
+NATIVE_LIBS += libc.so
+
# To work around a bootstrapping problem, we can't rely on cw(1) knowing how
# to translate -shared as we may be using an older one to build the current
# tools.
diff --git a/usr/src/ucblib/libucb/sparc/sys/signal.c b/usr/src/ucblib/libucb/sparc/sys/signal.c
index 3e8d414f85..dee23c3c4b 100644
--- a/usr/src/ucblib/libucb/sparc/sys/signal.c
+++ b/usr/src/ucblib/libucb/sparc/sys/signal.c
@@ -25,17 +25,13 @@
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
-/* All Rights Reserved */
+/* All Rights Reserved */
/*
* Portions of this source code were derived from Berkeley 4.3 BSD
* under license from the Regents of the University of California.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-/*LINTLIBRARY*/
-
/*
* 4.3BSD signal compatibility functions
*
@@ -480,12 +476,13 @@ ucbsigvec(int sig, struct sigvec *nvec, struct sigvec *ovec)
* This allows a child of vfork(2) to set signal handlers
* to SIG_IGN or SIG_DFL without affecting the parent.
*/
- if ((void (*)(int))nhandler != SIG_DFL &&
- (void (*)(int))nhandler != SIG_IGN) {
+ if ((void (*)(int))(uintptr_t)nhandler != SIG_DFL &&
+ (void (*)(int))(uintptr_t)nhandler != SIG_IGN) {
_siguhandler[sig] = nhandler;
- nact.sa_handler = (void (*)(int))ucbsigvechandler;
+ nact.sa_handler =
+ (void (*)(int))(uintptr_t)ucbsigvechandler;
} else {
- nact.sa_handler = (void (*)(int))nhandler;
+ nact.sa_handler = (void (*)(int))(uintptr_t)nhandler;
}
mask2set(nvec->sv_mask, &nact.sa_mask);
if (sig == SIGKILL || sig == SIGSTOP)
@@ -566,7 +563,8 @@ ucbsignal(int s, void (*a)(int)))(int)
static int mask[NSIG];
static int flags[NSIG];
- nsv.sv_handler = (void (*) (int, int, struct sigcontext *, char *)) a;
+ nsv.sv_handler =
+ (void (*) (int, int, struct sigcontext *, char *))(uintptr_t)a;
nsv.sv_mask = mask[s];
nsv.sv_flags = flags[s];
if (ucbsigvec(s, &nsv, &osv) < 0)
diff --git a/usr/src/uts/common/brand/lx/procfs/lx_proc.h b/usr/src/uts/common/brand/lx/procfs/lx_proc.h
index 723dfff560..be95e7e471 100644
--- a/usr/src/uts/common/brand/lx/procfs/lx_proc.h
+++ b/usr/src/uts/common/brand/lx/procfs/lx_proc.h
@@ -225,6 +225,7 @@ typedef enum lxpr_nodetype {
LXPR_SYS_KERNEL_RANDDIR, /* /proc/sys/kernel/random */
LXPR_SYS_KERNEL_RAND_BOOTID, /* /proc/sys/kernel/random/boot_id */
LXPR_SYS_KERNEL_RAND_ENTAVL, /* /proc/sys/kernel/random/entropy_avail */
+ LXPR_SYS_KERNEL_RAND_UUID, /* /proc/sys/kernel/random/uuid */
LXPR_SYS_KERNEL_SEM, /* /proc/sys/kernel/sem */
LXPR_SYS_KERNEL_SHMALL, /* /proc/sys/kernel/shmall */
LXPR_SYS_KERNEL_SHMMAX, /* /proc/sys/kernel/shmmax */
diff --git a/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c b/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c
index 575acd59a2..d573825652 100644
--- a/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c
+++ b/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c
@@ -248,6 +248,7 @@ static void lxpr_read_sys_kernel_osrel(lxpr_node_t *, lxpr_uiobuf_t *);
static void lxpr_read_sys_kernel_pid_max(lxpr_node_t *, lxpr_uiobuf_t *);
static void lxpr_read_sys_kernel_rand_bootid(lxpr_node_t *, lxpr_uiobuf_t *);
static void lxpr_read_sys_kernel_rand_entavl(lxpr_node_t *, lxpr_uiobuf_t *);
+static void lxpr_read_sys_kernel_rand_uuid(lxpr_node_t *, lxpr_uiobuf_t *);
static void lxpr_read_sys_kernel_sem(lxpr_node_t *, lxpr_uiobuf_t *);
static void lxpr_read_sys_kernel_shmall(lxpr_node_t *, lxpr_uiobuf_t *);
static void lxpr_read_sys_kernel_shmmax(lxpr_node_t *, lxpr_uiobuf_t *);
@@ -590,6 +591,7 @@ static lxpr_dirent_t sys_kerneldir[] = {
static lxpr_dirent_t sys_randdir[] = {
{ LXPR_SYS_KERNEL_RAND_BOOTID, "boot_id" },
{ LXPR_SYS_KERNEL_RAND_ENTAVL, "entropy_avail" },
+ { LXPR_SYS_KERNEL_RAND_UUID, "uuid" },
};
#define SYS_RANDDIRFILES (sizeof (sys_randdir) / sizeof (sys_randdir[0]))
@@ -932,6 +934,7 @@ static void (*lxpr_read_function[])() = {
lxpr_read_invalid, /* /proc/sys/kernel/random */
lxpr_read_sys_kernel_rand_bootid, /* /proc/sys/kernel/random/boot_id */
lxpr_read_sys_kernel_rand_entavl, /* .../kernel/random/entropy_avail */
+ lxpr_read_sys_kernel_rand_uuid, /* .../kernel/random/uuid */
lxpr_read_sys_kernel_sem, /* /proc/sys/kernel/sem */
lxpr_read_sys_kernel_shmall, /* /proc/sys/kernel/shmall */
lxpr_read_sys_kernel_shmmax, /* /proc/sys/kernel/shmmax */
@@ -1101,6 +1104,7 @@ static vnode_t *(*lxpr_lookup_function[])() = {
lxpr_lookup_sys_kdir_randdir, /* /proc/sys/kernel/random */
lxpr_lookup_not_a_dir, /* /proc/sys/kernel/random/boot_id */
lxpr_lookup_not_a_dir, /* .../kernel/random/entropy_avail */
+ lxpr_lookup_not_a_dir, /* /proc/sys/kernel/random/uuid */
lxpr_lookup_not_a_dir, /* /proc/sys/kernel/sem */
lxpr_lookup_not_a_dir, /* /proc/sys/kernel/shmall */
lxpr_lookup_not_a_dir, /* /proc/sys/kernel/shmmax */
@@ -1270,6 +1274,7 @@ static int (*lxpr_readdir_function[])() = {
lxpr_readdir_sys_kdir_randdir, /* /proc/sys/kernel/random */
lxpr_readdir_not_a_dir, /* /proc/sys/kernel/random/boot_id */
lxpr_readdir_not_a_dir, /* .../kernel/random/entropy_avail */
+ lxpr_readdir_not_a_dir, /* /proc/sys/kernel/random/uuid */
lxpr_readdir_not_a_dir, /* /proc/sys/kernel/sem */
lxpr_readdir_not_a_dir, /* /proc/sys/kernel/shmall */
lxpr_readdir_not_a_dir, /* /proc/sys/kernel/shmmax */
@@ -4923,7 +4928,25 @@ lxpr_read_sys_kernel_pid_max(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
lxpr_uiobuf_printf(uiobuf, "%d\n", maxpid);
}
-/* ARGSUSED */
+static void
+lxpr_gen_uuid(char *uuid, size_t size)
+{
+ uint8_t r[16];
+ if (random_get_bytes(r, sizeof (r)) != 0) {
+ (void) random_get_pseudo_bytes(r, sizeof (r));
+ }
+ /* Set UUID version to 4 (random) */
+ r[6] = 0x40 | (r[6] & 0x0f);
+ /* Set UUID variant to 1 */
+ r[8] = 0x80 | (r[8] & 0x3f);
+
+ (void) snprintf(uuid, size,
+ "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x"
+ "-%02x%02x%02x%02x%02x%02x",
+ r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7], r[8],
+ r[9], r[10], r[11], r[12], r[13], r[14], r[15]);
+}
+
static void
lxpr_read_sys_kernel_rand_bootid(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
{
@@ -4937,13 +4960,11 @@ lxpr_read_sys_kernel_rand_bootid(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
* safe choice if you need to identify a specific boot on a specific
* booted kernel.
*
- * We'll just generate a random ID if necessary. On Linux the format
- * appears to resemble a uuid but since it is not documented to be a
- * uuid, we don't worry about that.
+ * On Linux the format appears to resemble a uuid so stick with that.
*/
zone_t *zone = LXPTOZ(lxpnp);
lx_zone_data_t *lxzd = ztolxzd(zone);
- char bootid[LX_BOOTID_LEN];
+ char bootid[UUID_PRINTABLE_STRING_LENGTH];
ASSERT(lxpnp->lxpr_type == LXPR_SYS_KERNEL_RAND_BOOTID);
ASSERT(zone->zone_brand == &lx_brand);
@@ -4951,30 +4972,7 @@ lxpr_read_sys_kernel_rand_bootid(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
mutex_enter(&lxzd->lxzd_lock);
if (lxzd->lxzd_bootid[0] == '\0') {
- int i;
-
- for (i = 0; i < 5; i++) {
- u_longlong_t n;
- char s[32];
-
- (void) random_get_bytes((uint8_t *)&n, sizeof (n));
- switch (i) {
- case 0: (void) snprintf(s, sizeof (s), "%08llx", n);
- s[8] = '\0';
- break;
- case 4: (void) snprintf(s, sizeof (s), "%012llx", n);
- s[12] = '\0';
- break;
- default: (void) snprintf(s, sizeof (s), "%04llx", n);
- s[4] = '\0';
- break;
- }
- if (i > 0)
- (void) strlcat(lxzd->lxzd_bootid, "-",
- sizeof (lxzd->lxzd_bootid));
- (void) strlcat(lxzd->lxzd_bootid, s,
- sizeof (lxzd->lxzd_bootid));
- }
+ lxpr_gen_uuid(lxzd->lxzd_bootid, sizeof (lxzd->lxzd_bootid));
}
(void) strlcpy(bootid, lxzd->lxzd_bootid, sizeof (bootid));
mutex_exit(&lxzd->lxzd_lock);
@@ -4995,6 +4993,24 @@ lxpr_read_sys_kernel_rand_entavl(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
lxpr_uiobuf_printf(uiobuf, "%d\n", swrand_stats.ss_entEst);
}
+static void
+lxpr_read_sys_kernel_rand_uuid(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
+{
+ /*
+ * Each read from this read-only file should return a new
+ * random 128-bit UUID string in the standard UUID format.
+ */
+ zone_t *zone = LXPTOZ(lxpnp);
+ char uuid[UUID_PRINTABLE_STRING_LENGTH];
+
+ ASSERT(lxpnp->lxpr_type == LXPR_SYS_KERNEL_RAND_UUID);
+ ASSERT(zone->zone_brand == &lx_brand);
+
+ lxpr_gen_uuid(uuid, sizeof (uuid));
+
+ lxpr_uiobuf_printf(uiobuf, "%s\n", uuid);
+}
+
/* ARGSUSED */
static void
lxpr_read_sys_kernel_sem(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
diff --git a/usr/src/uts/common/brand/lx/sys/lx_brand.h b/usr/src/uts/common/brand/lx/sys/lx_brand.h
index 85aa5e34bd..35b1bddb03 100644
--- a/usr/src/uts/common/brand/lx/sys/lx_brand.h
+++ b/usr/src/uts/common/brand/lx/sys/lx_brand.h
@@ -41,6 +41,7 @@
#include <sys/cpuvar.h>
#include <sys/lx_futex.h>
#include <sys/lx_userhz.h>
+#include <sys/uuid.h>
#endif
#ifdef __cplusplus
@@ -397,9 +398,6 @@ typedef struct lx_proc_data {
#define LX_AFF_ULONGS (LX_NCPU / (8 * sizeof (ulong_t)))
typedef ulong_t lx_affmask_t[LX_AFF_ULONGS];
-/* Length of proc boot_id string */
-#define LX_BOOTID_LEN 37
-
/*
* Flag values for uc_brand_data[0] in the ucontext_t:
*/
@@ -637,7 +635,7 @@ typedef struct lx_zone_data {
char lxzd_kernel_release[LX_KERN_RELEASE_MAX];
char lxzd_kernel_version[LX_KERN_VERSION_MAX];
ksocket_t lxzd_ioctl_sock;
- char lxzd_bootid[LX_BOOTID_LEN]; /* procfs boot_id */
+ char lxzd_bootid[UUID_PRINTABLE_STRING_LENGTH]; /* procfs boot_id */
gid_t lxzd_ttygrp; /* tty gid for pty chown */
vfs_t *lxzd_cgroup; /* cgroup for this zone */
pid_t lxzd_lockd_pid; /* pid of NFS lockd */
diff --git a/usr/src/uts/common/io/mlxcx/mlxcx.c b/usr/src/uts/common/io/mlxcx/mlxcx.c
index 9aae5244de..f74d093b9c 100644
--- a/usr/src/uts/common/io/mlxcx/mlxcx.c
+++ b/usr/src/uts/common/io/mlxcx/mlxcx.c
@@ -10,7 +10,7 @@
*/
/*
- * Copyright 2020, The University of Queensland
+ * Copyright 2021, The University of Queensland
* Copyright (c) 2018, Joyent, Inc.
* Copyright 2020 RackTop Systems, Inc.
*/
@@ -2365,12 +2365,28 @@ mlxcx_setup_eq(mlxcx_t *mlxp, uint_t vec, uint64_t events)
return (B_FALSE);
}
mleq->mleq_state |= MLXCX_EQ_INTR_ENABLED;
+ mleq->mleq_state |= MLXCX_EQ_ATTACHING;
mlxcx_arm_eq(mlxp, mleq);
mutex_exit(&mleq->mleq_mtx);
return (B_TRUE);
}
+static void
+mlxcx_eq_set_attached(mlxcx_t *mlxp)
+{
+ uint_t vec;
+ mlxcx_event_queue_t *mleq;
+
+ for (vec = 0; vec < mlxp->mlx_intr_count; ++vec) {
+ mleq = &mlxp->mlx_eqs[vec];
+
+ mutex_enter(&mleq->mleq_mtx);
+ mleq->mleq_state &= ~MLXCX_EQ_ATTACHING;
+ mutex_exit(&mleq->mleq_mtx);
+ }
+}
+
static boolean_t
mlxcx_setup_async_eqs(mlxcx_t *mlxp)
{
@@ -2764,7 +2780,10 @@ mlxcx_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
* Set up asynchronous event queue which handles control type events
* like PAGE_REQUEST and CMD completion events.
*
- * This will enable and arm the interrupt on EQ 0.
+ * This will enable and arm the interrupt on EQ 0. Note that only page
+ * reqs and cmd completions will be handled until we call
+ * mlxcx_eq_set_attached further down (this way we don't need an extra
+ * set of locks over the mlxcx_t sub-structs not allocated yet)
*/
if (!mlxcx_setup_async_eqs(mlxp)) {
goto err;
@@ -2891,6 +2910,12 @@ mlxcx_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
}
mlxp->mlx_attach |= MLXCX_ATTACH_MAC_HDL;
+ /*
+ * This tells the interrupt handlers they can start processing events
+ * other than cmd completions and page requests.
+ */
+ mlxcx_eq_set_attached(mlxp);
+
return (DDI_SUCCESS);
err:
diff --git a/usr/src/uts/common/io/mlxcx/mlxcx.h b/usr/src/uts/common/io/mlxcx/mlxcx.h
index e28fe89806..68da65765f 100644
--- a/usr/src/uts/common/io/mlxcx/mlxcx.h
+++ b/usr/src/uts/common/io/mlxcx/mlxcx.h
@@ -10,7 +10,7 @@
*/
/*
- * Copyright 2020, The University of Queensland
+ * Copyright 2021, The University of Queensland
* Copyright (c) 2018, Joyent, Inc.
* Copyright 2020 RackTop Systems, Inc.
*/
@@ -318,6 +318,7 @@ typedef enum {
MLXCX_EQ_INTR_ENABLED = 1 << 5, /* ddi_intr_enable()'d */
MLXCX_EQ_INTR_ACTIVE = 1 << 6, /* 'rupt handler running */
MLXCX_EQ_INTR_QUIESCE = 1 << 7, /* 'rupt handler to quiesce */
+ MLXCX_EQ_ATTACHING = 1 << 8, /* mlxcx_attach still running */
} mlxcx_eventq_state_t;
typedef struct mlxcx_bf {
diff --git a/usr/src/uts/common/io/mlxcx/mlxcx_gld.c b/usr/src/uts/common/io/mlxcx/mlxcx_gld.c
index 941eb0f9e7..2c41f4ddeb 100644
--- a/usr/src/uts/common/io/mlxcx/mlxcx_gld.c
+++ b/usr/src/uts/common/io/mlxcx/mlxcx_gld.c
@@ -10,7 +10,7 @@
*/
/*
- * Copyright (c) 2020, the University of Queensland
+ * Copyright (c) 2021, the University of Queensland
* Copyright 2020 RackTop Systems, Inc.
*/
@@ -1493,6 +1493,8 @@ mlxcx_register_mac(mlxcx_t *mlxp)
VERIFY3U(mlxp->mlx_nports, ==, 1);
port = &mlxp->mlx_ports[0];
+ mutex_enter(&port->mlp_mtx);
+
mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
mac->m_driver = mlxp;
mac->m_dip = mlxp->mlx_dip;
@@ -1510,6 +1512,8 @@ mlxcx_register_mac(mlxcx_t *mlxp)
}
mac_free(mac);
+ mutex_exit(&port->mlp_mtx);
+
mlxcx_update_link_state(mlxp, port);
return (ret == 0);
diff --git a/usr/src/uts/common/io/mlxcx/mlxcx_intr.c b/usr/src/uts/common/io/mlxcx/mlxcx_intr.c
index 53ea4d683e..e2f5141171 100644
--- a/usr/src/uts/common/io/mlxcx/mlxcx_intr.c
+++ b/usr/src/uts/common/io/mlxcx/mlxcx_intr.c
@@ -10,7 +10,7 @@
*/
/*
- * Copyright (c) 2020, the University of Queensland
+ * Copyright (c) 2021, the University of Queensland
* Copyright 2020 RackTop Systems, Inc.
* Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
*/
@@ -422,7 +422,9 @@ mlxcx_update_link_state(mlxcx_t *mlxp, mlxcx_port_t *port)
default:
ls = LINK_STATE_UNKNOWN;
}
- mac_link_update(mlxp->mlx_mac_hdl, ls);
+
+ if (mlxp->mlx_mac_hdl != NULL)
+ mac_link_update(mlxp->mlx_mac_hdl, ls);
mutex_exit(&port->mlp_mtx);
}
@@ -762,10 +764,16 @@ mlxcx_intr_async(caddr_t arg, caddr_t arg2)
DTRACE_PROBE2(event, mlxcx_t *, mlxp, mlxcx_eventq_ent_t *,
ent);
+ /*
+ * Handle events which can be processed while we're still in
+ * mlxcx_attach(). Everything on the mlxcx_t which these events
+ * use must be allocated and set up prior to the call to
+ * mlxcx_setup_async_eqs().
+ */
switch (ent->mleqe_event_type) {
case MLXCX_EVENT_CMD_COMPLETION:
mlxcx_cmd_completion(mlxp, ent);
- break;
+ continue;
case MLXCX_EVENT_PAGE_REQUEST:
func = from_be16(ent->mleqe_page_request.
mled_page_request_function_id);
@@ -783,7 +791,7 @@ mlxcx_intr_async(caddr_t arg, caddr_t arg2)
mutex_exit(&param->mla_mtx);
mlxcx_warn(mlxp, "Unexpected page request "
"whilst another is pending");
- break;
+ continue;
}
param->mla_pages.mlp_npages =
(int32_t)from_be32(ent->mleqe_page_request.
@@ -795,7 +803,20 @@ mlxcx_intr_async(caddr_t arg, caddr_t arg2)
taskq_dispatch_ent(mlxp->mlx_async_tq, mlxcx_pages_task,
param, 0, &param->mla_tqe);
- break;
+ continue;
+ }
+
+ /*
+ * All other events should be ignored while in attach.
+ */
+ mutex_enter(&mleq->mleq_mtx);
+ if (mleq->mleq_state & MLXCX_EQ_ATTACHING) {
+ mutex_exit(&mleq->mleq_mtx);
+ continue;
+ }
+ mutex_exit(&mleq->mleq_mtx);
+
+ switch (ent->mleqe_event_type) {
case MLXCX_EVENT_PORT_STATE:
portn = get_bits8(
ent->mleqe_port_state.mled_port_state_port_num,
@@ -1055,17 +1076,30 @@ mlxcx_intr_n(caddr_t arg, caddr_t arg2)
}
mleq->mleq_badintrs = 0;
+ mutex_enter(&mleq->mleq_mtx);
ASSERT(mleq->mleq_state & MLXCX_EQ_ARMED);
mleq->mleq_state &= ~MLXCX_EQ_ARMED;
+#if defined(DEBUG)
+ /*
+ * If we're still in mlxcx_attach and an intr_n fired, something really
+ * weird is going on. This shouldn't happen in the absence of a driver
+ * or firmware bug, so in the interests of minimizing branches in this
+ * function this check is under DEBUG.
+ */
+ if (mleq->mleq_state & MLXCX_EQ_ATTACHING) {
+ mutex_exit(&mleq->mleq_mtx);
+ mlxcx_warn(mlxp, "intr_n (%u) fired during attach, disabling "
+ "vector", mleq->mleq_intr_index);
+ mlxcx_fm_ereport(mlxp, DDI_FM_DEVICE_INVAL_STATE);
+ ddi_fm_service_impact(mlxp->mlx_dip, DDI_SERVICE_LOST);
+ (void) ddi_intr_disable(mlxp->mlx_intr_handles[
+ mleq->mleq_intr_index]);
+ goto done;
+ }
+#endif
+ mutex_exit(&mleq->mleq_mtx);
for (; ent != NULL; ent = mlxcx_eq_next(mleq)) {
- if (ent->mleqe_event_type != MLXCX_EVENT_COMPLETION) {
- mlxcx_fm_ereport(mlxp, DDI_FM_DEVICE_INVAL_STATE);
- ddi_fm_service_impact(mlxp->mlx_dip, DDI_SERVICE_LOST);
- (void) ddi_intr_disable(mlxp->mlx_intr_handles[
- mleq->mleq_intr_index]);
- goto done;
- }
ASSERT3U(ent->mleqe_event_type, ==, MLXCX_EVENT_COMPLETION);
probe.mlcq_num =
@@ -1075,7 +1109,7 @@ mlxcx_intr_n(caddr_t arg, caddr_t arg2)
mutex_exit(&mleq->mleq_mtx);
if (mlcq == NULL)
- continue;
+ goto update_eq;
mlwq = mlcq->mlcq_wq;
diff --git a/usr/src/uts/common/io/nvme/nvme.c b/usr/src/uts/common/io/nvme/nvme.c
index 89debf9b07..8215adaed6 100644
--- a/usr/src/uts/common/io/nvme/nvme.c
+++ b/usr/src/uts/common/io/nvme/nvme.c
@@ -1103,6 +1103,22 @@ nvme_submit_cmd_common(nvme_qpair_t *qp, nvme_cmd_t *cmd)
cmd->nc_completed = B_FALSE;
/*
+ * Now that we hold the queue pair lock, we must check whether or not
+ * the controller has been listed as dead (e.g. was removed due to
+ * hotplug). This is necessary as otherwise we could race with
+ * nvme_remove_callback(). Because this has not been enqueued, we don't
+ * call nvme_unqueue_cmd(), which is why we must manually decrement the
+ * semaphore.
+ */
+ if (cmd->nc_nvme->n_dead) {
+ taskq_dispatch_ent(qp->nq_cq->ncq_cmd_taskq, cmd->nc_callback,
+ cmd, TQ_NOSLEEP, &cmd->nc_tqent);
+ sema_v(&qp->nq_sema);
+ mutex_exit(&qp->nq_mutex);
+ return;
+ }
+
+ /*
* Try to insert the cmd into the active cmd array at the nq_next_cmd
* slot. If the slot is already occupied advance to the next slot and
* try again. This can happen for long running commands like async event
diff --git a/usr/src/uts/common/io/pciex/pcie.c b/usr/src/uts/common/io/pciex/pcie.c
index 35a0190be7..df6b2d189b 100644
--- a/usr/src/uts/common/io/pciex/pcie.c
+++ b/usr/src/uts/common/io/pciex/pcie.c
@@ -22,6 +22,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2019 Joyent, Inc.
+ * Copyright 2021 Oxide Computer Company
*/
#include <sys/sysmacros.h>
@@ -1189,11 +1190,18 @@ pcie_capture_speeds(dev_info_t *dip)
uint16_t vers, status;
uint32_t cap, cap2, ctl2;
pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
+ dev_info_t *rcdip;
if (!PCIE_IS_PCIE(bus_p))
return;
- vers = PCIE_CAP_GET(16, bus_p, PCIE_PCIECAP);
+ rcdip = pcie_get_rc_dip(dip);
+ if (bus_p->bus_cfg_hdl == NULL) {
+ vers = pci_cfgacc_get16(rcdip, bus_p->bus_bdf,
+ bus_p->bus_pcie_off + PCIE_PCIECAP);
+ } else {
+ vers = PCIE_CAP_GET(16, bus_p, PCIE_PCIECAP);
+ }
if (vers == PCI_EINVAL16)
return;
vers &= PCIE_PCIECAP_VER_MASK;
@@ -1207,10 +1215,17 @@ pcie_capture_speeds(dev_info_t *dip)
ctl2 = 0;
break;
case PCIE_PCIECAP_VER_2_0:
- cap2 = PCIE_CAP_GET(32, bus_p, PCIE_LINKCAP2);
+ if (bus_p->bus_cfg_hdl == NULL) {
+ cap2 = pci_cfgacc_get32(rcdip, bus_p->bus_bdf,
+ bus_p->bus_pcie_off + PCIE_LINKCAP2);
+ ctl2 = pci_cfgacc_get16(rcdip, bus_p->bus_bdf,
+ bus_p->bus_pcie_off + PCIE_LINKCTL2);
+ } else {
+ cap2 = PCIE_CAP_GET(32, bus_p, PCIE_LINKCAP2);
+ ctl2 = PCIE_CAP_GET(16, bus_p, PCIE_LINKCTL2);
+ }
if (cap2 == PCI_EINVAL32)
cap2 = 0;
- ctl2 = PCIE_CAP_GET(16, bus_p, PCIE_LINKCTL2);
if (ctl2 == PCI_EINVAL16)
ctl2 = 0;
break;
@@ -1219,8 +1234,15 @@ pcie_capture_speeds(dev_info_t *dip)
return;
}
- status = PCIE_CAP_GET(16, bus_p, PCIE_LINKSTS);
- cap = PCIE_CAP_GET(32, bus_p, PCIE_LINKCAP);
+ if (bus_p->bus_cfg_hdl == NULL) {
+ status = pci_cfgacc_get16(rcdip, bus_p->bus_bdf,
+ bus_p->bus_pcie_off + PCIE_LINKSTS);
+ cap = pci_cfgacc_get32(rcdip, bus_p->bus_bdf,
+ bus_p->bus_pcie_off + PCIE_LINKCAP);
+ } else {
+ status = PCIE_CAP_GET(16, bus_p, PCIE_LINKSTS);
+ cap = PCIE_CAP_GET(32, bus_p, PCIE_LINKCAP);
+ }
if (status == PCI_EINVAL16 || cap == PCI_EINVAL32)
return;
@@ -1659,6 +1681,8 @@ initial_done:
pcie_init_plat(dip);
+ pcie_capture_speeds(dip);
+
final_done:
PCIE_DBG("Add %s(dip 0x%p, bdf 0x%x, secbus 0x%x)\n",
diff --git a/usr/src/uts/common/io/vioif/vioif.c b/usr/src/uts/common/io/vioif/vioif.c
index cac90d3073..368af5381d 100644
--- a/usr/src/uts/common/io/vioif/vioif.c
+++ b/usr/src/uts/common/io/vioif/vioif.c
@@ -12,7 +12,7 @@
/*
* Copyright 2013 Nexenta Inc. All rights reserved.
* Copyright (c) 2014, 2016 by Delphix. All rights reserved.
- * Copyright 2019 Joyent, Inc.
+ * Copyright 2021 Joyent, Inc.
* Copyright 2019 Joshua M. Clulow <josh@sysmgr.org>
*/
@@ -328,6 +328,32 @@ vioif_rx_free_callback(caddr_t free_arg)
mutex_exit(&vif->vif_mutex);
}
+static vioif_ctrlbuf_t *
+vioif_ctrlbuf_alloc(vioif_t *vif)
+{
+ vioif_ctrlbuf_t *cb;
+
+ VERIFY(MUTEX_HELD(&vif->vif_mutex));
+
+ if ((cb = list_remove_head(&vif->vif_ctrlbufs)) != NULL) {
+ vif->vif_nctrlbufs_alloc++;
+ }
+
+ return (cb);
+}
+
+static void
+vioif_ctrlbuf_free(vioif_t *vif, vioif_ctrlbuf_t *cb)
+{
+ VERIFY(MUTEX_HELD(&vif->vif_mutex));
+
+ VERIFY3U(vif->vif_nctrlbufs_alloc, >, 0);
+ vif->vif_nctrlbufs_alloc--;
+
+ virtio_chain_clear(cb->cb_chain);
+ list_insert_head(&vif->vif_ctrlbufs, cb);
+}
+
static void
vioif_free_bufs(vioif_t *vif)
{
@@ -408,6 +434,37 @@ vioif_free_bufs(vioif_t *vif)
vif->vif_rxbufs_mem = NULL;
vif->vif_rxbufs_capacity = 0;
}
+
+ if (vif->vif_has_ctrlq) {
+ VERIFY3U(vif->vif_nctrlbufs_alloc, ==, 0);
+ for (uint_t i = 0; i < vif->vif_ctrlbufs_capacity; i++) {
+ vioif_ctrlbuf_t *cb = &vif->vif_ctrlbufs_mem[i];
+
+ /*
+ * Ensure that this ctrlbuf is now in the free list
+ */
+ VERIFY(list_link_active(&cb->cb_link));
+ list_remove(&vif->vif_ctrlbufs, cb);
+
+ if (cb->cb_dma != NULL) {
+ virtio_dma_free(cb->cb_dma);
+ cb->cb_dma = NULL;
+ }
+
+ if (cb->cb_chain != NULL) {
+ virtio_chain_free(cb->cb_chain);
+ cb->cb_chain = NULL;
+ }
+ }
+ VERIFY(list_is_empty(&vif->vif_ctrlbufs));
+ if (vif->vif_ctrlbufs_mem != NULL) {
+ kmem_free(vif->vif_ctrlbufs_mem,
+ sizeof (vioif_ctrlbuf_t) *
+ vif->vif_ctrlbufs_capacity);
+ vif->vif_ctrlbufs_mem = NULL;
+ vif->vif_ctrlbufs_capacity = 0;
+ }
+ }
}
static int
@@ -434,6 +491,16 @@ vioif_alloc_bufs(vioif_t *vif)
list_create(&vif->vif_rxbufs, sizeof (vioif_rxbuf_t),
offsetof(vioif_rxbuf_t, rb_link));
+ if (vif->vif_has_ctrlq) {
+ vif->vif_ctrlbufs_capacity = MIN(VIRTIO_NET_CTRL_BUFS,
+ virtio_queue_size(vif->vif_ctrl_vq));
+ vif->vif_ctrlbufs_mem = kmem_zalloc(
+ sizeof (vioif_ctrlbuf_t) * vif->vif_ctrlbufs_capacity,
+ KM_SLEEP);
+ }
+ list_create(&vif->vif_ctrlbufs, sizeof (vioif_ctrlbuf_t),
+ offsetof(vioif_ctrlbuf_t, cb_link));
+
/*
* Do not loan more than half of our allocated receive buffers into
* the networking stack.
@@ -450,6 +517,9 @@ vioif_alloc_bufs(vioif_t *vif)
for (uint_t i = 0; i < vif->vif_rxbufs_capacity; i++) {
list_insert_tail(&vif->vif_rxbufs, &vif->vif_rxbufs_mem[i]);
}
+ for (uint_t i = 0; i < vif->vif_ctrlbufs_capacity; i++) {
+ list_insert_tail(&vif->vif_ctrlbufs, &vif->vif_ctrlbufs_mem[i]);
+ }
/*
* Start from the DMA attribute template common to both transmit and
@@ -486,6 +556,26 @@ vioif_alloc_bufs(vioif_t *vif)
}
/*
+ * Control queue buffers are also small (less than a page), so we'll
+ * also request a single cookie for them.
+ */
+ for (vioif_ctrlbuf_t *cb = list_head(&vif->vif_ctrlbufs); cb != NULL;
+ cb = list_next(&vif->vif_ctrlbufs, cb)) {
+ if ((cb->cb_dma = virtio_dma_alloc(vif->vif_virtio,
+ VIOIF_CTRL_SIZE, &attr,
+ DDI_DMA_STREAMING | DDI_DMA_RDWR, KM_SLEEP)) == NULL) {
+ goto fail;
+ }
+ VERIFY3U(virtio_dma_ncookies(cb->cb_dma), ==, 1);
+
+ if ((cb->cb_chain = virtio_chain_alloc(vif->vif_ctrl_vq,
+ KM_SLEEP)) == NULL) {
+ goto fail;
+ }
+ virtio_chain_data_set(cb->cb_chain, cb);
+ }
+
+ /*
* The receive buffers are larger, and we can tolerate a large number
* of segments. Adjust the SGL entry count, setting aside one segment
* for the virtio net header.
@@ -533,6 +623,128 @@ fail:
}
static int
+vioif_ctrlq_req(vioif_t *vif, uint8_t class, uint8_t cmd, void *data,
+ size_t datalen)
+{
+ vioif_ctrlbuf_t *cb = NULL;
+ virtio_chain_t *vic = NULL;
+ uint8_t *p = NULL;
+ uint64_t pa = 0;
+ uint8_t *ackp = NULL;
+ struct virtio_net_ctrlq_hdr hdr = {
+ .vnch_class = class,
+ .vnch_command = cmd,
+ };
+ const size_t hdrlen = sizeof (hdr);
+ const size_t acklen = 1; /* the ack is always 1 byte */
+ size_t totlen = hdrlen + datalen + acklen;
+ int r = DDI_SUCCESS;
+
+ /*
+ * We shouldn't be called unless the ctrlq feature has been
+ * negotiated with the host
+ */
+ VERIFY(vif->vif_has_ctrlq);
+
+ mutex_enter(&vif->vif_mutex);
+ cb = vioif_ctrlbuf_alloc(vif);
+ if (cb == NULL) {
+ vif->vif_noctrlbuf++;
+ mutex_exit(&vif->vif_mutex);
+ r = DDI_FAILURE;
+ goto done;
+ }
+ mutex_exit(&vif->vif_mutex);
+
+ if (totlen > virtio_dma_size(cb->cb_dma)) {
+ vif->vif_ctrlbuf_toosmall++;
+ r = DDI_FAILURE;
+ goto done;
+ }
+
+ /*
+ * Clear the entire buffer. Technically not necessary, but useful
+ * if trying to troubleshoot an issue, and probably not a bad idea
+ * to not let any old data linger.
+ */
+ p = virtio_dma_va(cb->cb_dma, 0);
+ bzero(p, virtio_dma_size(cb->cb_dma));
+
+ /*
+ * We currently do not support VIRTIO_F_ANY_LAYOUT. That means,
+ * that we must put the header, the data, and the ack in their
+ * own respective descriptors. Since all the currently supported
+ * control queue commands take _very_ small amounts of data, we
+ * use a single DMA buffer for all of it, but use 3 descriptors to
+ * reference (respectively) the header, the data, and the ack byte
+ * within that memory to adhere to the virtio spec.
+ *
+ * If we add support for control queue features such as custom
+ * MAC filtering tables, which might require larger amounts of
+ * memory, we likely will want to add more sophistication here
+ * and optionally use additional allocated memory to hold that
+ * data instead of a fixed size buffer.
+ *
+ * Copy the header.
+ */
+ bcopy(&hdr, p, sizeof (hdr));
+ pa = virtio_dma_cookie_pa(cb->cb_dma, 0);
+ if ((r = virtio_chain_append(cb->cb_chain,
+ pa, hdrlen, VIRTIO_DIR_DEVICE_READS)) != DDI_SUCCESS) {
+ goto done;
+ }
+
+ /*
+ * Copy the request data
+ */
+ p = virtio_dma_va(cb->cb_dma, hdrlen);
+ bcopy(data, p, datalen);
+ if ((r = virtio_chain_append(cb->cb_chain,
+ pa + hdrlen, datalen, VIRTIO_DIR_DEVICE_READS)) != DDI_SUCCESS) {
+ goto done;
+ }
+
+ /*
+ * We already cleared the buffer, so don't need to copy out a 0 for
+ * the ack byte. Just add a descriptor for that spot.
+ */
+ ackp = virtio_dma_va(cb->cb_dma, hdrlen + datalen);
+ if ((r = virtio_chain_append(cb->cb_chain,
+ pa + hdrlen + datalen, acklen,
+ VIRTIO_DIR_DEVICE_WRITES)) != DDI_SUCCESS) {
+ goto done;
+ }
+
+ virtio_dma_sync(cb->cb_dma, DDI_DMA_SYNC_FORDEV);
+ virtio_chain_submit(cb->cb_chain, B_TRUE);
+
+ /*
+ * Spin waiting for response.
+ */
+ mutex_enter(&vif->vif_mutex);
+ while ((vic = virtio_queue_poll(vif->vif_ctrl_vq)) == NULL) {
+ mutex_exit(&vif->vif_mutex);
+ delay(drv_usectohz(1000));
+ mutex_enter(&vif->vif_mutex);
+ }
+
+ virtio_dma_sync(cb->cb_dma, DDI_DMA_SYNC_FORCPU);
+ VERIFY3P(virtio_chain_data(vic), ==, cb);
+ mutex_exit(&vif->vif_mutex);
+
+ if (*ackp != VIRTIO_NET_CQ_OK) {
+ r = DDI_FAILURE;
+ }
+
+done:
+ mutex_enter(&vif->vif_mutex);
+ vioif_ctrlbuf_free(vif, cb);
+ mutex_exit(&vif->vif_mutex);
+
+ return (r);
+}
+
+static int
vioif_m_multicst(void *arg, boolean_t add, const uint8_t *mcst_addr)
{
/*
@@ -549,11 +761,25 @@ vioif_m_multicst(void *arg, boolean_t add, const uint8_t *mcst_addr)
static int
vioif_m_setpromisc(void *arg, boolean_t on)
{
- /*
- * Even though we cannot currently enable promiscuous mode, we return
- * success here to allow tools like snoop(1M) to continue to function.
- */
- return (0);
+ vioif_t *vif = arg;
+ uint8_t val = on ? 1 : 0;
+
+ if (!vif->vif_has_ctrlq_rx) {
+ /*
+ * While most hypervisors support the control queue, bhyve
+ * (or more specifically viona) on illumos currently does not.
+ *
+ * Until that support is added to viona, we pretend
+ * the request always succeeds to match the historic behavior
+ * of the illumos vioif driver. Once that support has been
+ * added to viona, we should do the correct thing and return
+ * ENOTSUP
+ */
+ return (0);
+ }
+
+ return (vioif_ctrlq_req(vif, VIRTIO_NET_CTRL_RX,
+ VIRTIO_NET_CTRL_RX_PROMISC, &val, sizeof (val)));
}
static int
@@ -1655,6 +1881,17 @@ vioif_check_features(vioif_t *vif)
vif->vif_tx_tso6 = 1;
}
}
+
+ if (vioif_has_feature(vif, VIRTIO_NET_F_CTRL_VQ)) {
+ vif->vif_has_ctrlq = 1;
+
+ /*
+ * The VIRTIO_NET_F_CTRL_VQ feature must be enabled if there's
+ * any chance of the VIRTIO_NET_F_CTRL_RX being enabled.
+ */
+ if (vioif_has_feature(vif, VIRTIO_NET_F_CTRL_RX))
+ vif->vif_has_ctrlq_rx = 1;
+ }
}
static int
@@ -1726,6 +1963,13 @@ vioif_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
goto fail;
}
+ if (vioif_has_feature(vif, VIRTIO_NET_F_CTRL_VQ) &&
+ (vif->vif_ctrl_vq = virtio_queue_alloc(vio,
+ VIRTIO_NET_VIRTQ_CONTROL, "ctrlq", NULL, vif,
+ B_FALSE, VIOIF_MAX_SEGS)) == NULL) {
+ goto fail;
+ }
+
if (virtio_init_complete(vio, vioif_select_interrupt_types()) !=
DDI_SUCCESS) {
dev_err(dip, CE_WARN, "failed to complete Virtio init");
@@ -1734,6 +1978,8 @@ vioif_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
virtio_queue_no_interrupt(vif->vif_rx_vq, B_TRUE);
virtio_queue_no_interrupt(vif->vif_tx_vq, B_TRUE);
+ if (vif->vif_ctrl_vq != NULL)
+ virtio_queue_no_interrupt(vif->vif_ctrl_vq, B_TRUE);
mutex_init(&vif->vif_mutex, NULL, MUTEX_DRIVER, virtio_intr_pri(vio));
mutex_enter(&vif->vif_mutex);
diff --git a/usr/src/uts/common/io/vioif/vioif.h b/usr/src/uts/common/io/vioif/vioif.h
index 9f750c9b8a..8e7dae320c 100644
--- a/usr/src/uts/common/io/vioif/vioif.h
+++ b/usr/src/uts/common/io/vioif/vioif.h
@@ -10,7 +10,7 @@
*/
/*
- * Copyright 2019 Joyent, Inc.
+ * Copyright 2021 Joyent, Inc.
*/
/*
@@ -167,7 +167,9 @@ extern "C" {
VIRTIO_NET_F_HOST_TSO6 | \
VIRTIO_NET_F_HOST_ECN | \
VIRTIO_NET_F_MAC | \
- VIRTIO_NET_F_MTU)
+ VIRTIO_NET_F_MTU | \
+ VIRTIO_NET_F_CTRL_VQ | \
+ VIRTIO_NET_F_CTRL_RX)
/*
* VIRTIO NETWORK HEADER
@@ -201,6 +203,37 @@ struct virtio_net_hdr {
#define VIRTIO_NET_HDR_GSO_TCPV6 4
#define VIRTIO_NET_HDR_GSO_ECN 0x80
+/*
+ * VIRTIO CONTROL VIRTQUEUE HEADER
+ *
+ * This structure appears at the start of each control virtqueue request.
+ */
+struct virtio_net_ctrlq_hdr {
+ uint8_t vnch_class;
+ uint8_t vnch_command;
+} __packed;
+
+/*
+ * Contol Queue Classes
+ */
+#define VIRTIO_NET_CTRL_RX 0
+
+/*
+ * CTRL_RX commands
+ */
+#define VIRTIO_NET_CTRL_RX_PROMISC 0
+#define VIRTIO_NET_CTRL_RX_ALLMULTI 1
+#define VIRTIO_NET_CTRL_RX_ALLUNI 2
+#define VIRTIO_NET_CTRL_RX_NOMULTI 3
+#define VIRTIO_NET_CTRL_RX_NOUNI 4
+#define VIRTIO_NET_CTRL_RX_NOBCAST 5
+
+/*
+ * Control queue ack values
+ */
+#define VIRTIO_NET_CQ_OK 0
+#define VIRTIO_NET_CQ_ERR 1
+
/*
* DRIVER PARAMETERS
@@ -216,6 +249,13 @@ struct virtio_net_hdr {
#define VIRTIO_NET_RX_BUFS 256
/*
+ * Initially, only use a single buf for control queue requests (when
+ * present). If this becomes a bottleneck, we can simply increase this
+ * value as necessary.
+ */
+#define VIRTIO_NET_CTRL_BUFS 1
+
+/*
* The virtio net header and the first buffer segment share the same DMA
* allocation. We round up the virtio header size to a multiple of 4 and add 2
* bytes so that the IP header, which starts immediately after the 14 or 18
@@ -261,6 +301,12 @@ struct virtio_net_hdr {
*/
#define VIOIF_TX_INLINE_SIZE (2 * 1024)
+/*
+ * Control queue messages are very small. This is a rather arbitrary small
+ * bufer size that should be sufficiently large for any control queue
+ * messages we will send.
+ */
+#define VIOIF_CTRL_SIZE 256
/*
* TYPE DEFINITIONS
@@ -289,6 +335,15 @@ typedef struct vioif_rxbuf {
list_node_t rb_link;
} vioif_rxbuf_t;
+typedef struct vioif_ctrlbuf {
+ vioif_t *cb_vioif;
+
+ virtio_dma_t *cb_dma;
+ virtio_chain_t *cb_chain;
+
+ list_node_t cb_link;
+} vioif_ctrlbuf_t;
+
/*
* Transmit buffers are also allocated in advance. DMA memory is allocated for
* the virtio net header, and to hold small packets. Larger packets are mapped
@@ -346,6 +401,7 @@ struct vioif {
virtio_queue_t *vif_rx_vq;
virtio_queue_t *vif_tx_vq;
+ virtio_queue_t *vif_ctrl_vq;
/* TX virtqueue management resources */
boolean_t vif_tx_corked;
@@ -366,6 +422,9 @@ struct vioif {
*/
unsigned int vif_mac_from_host:1;
+ unsigned int vif_has_ctrlq:1;
+ unsigned int vif_has_ctrlq_rx:1;
+
uint_t vif_mtu;
uint_t vif_mtu_max;
uint8_t vif_mac[ETHERADDRL];
@@ -395,6 +454,11 @@ struct vioif {
uint_t vif_rxcopy_thresh;
uint_t vif_txcopy_thresh;
+ list_t vif_ctrlbufs;
+ uint_t vif_nctrlbufs_alloc;
+ uint_t vif_ctrlbufs_capacity;
+ vioif_ctrlbuf_t *vif_ctrlbufs_mem;
+
/*
* Statistics visible through mac:
*/
@@ -424,6 +488,9 @@ struct vioif {
uint64_t vif_txfail_indirect_limit;
uint64_t vif_stat_tx_reclaim;
+
+ uint64_t vif_noctrlbuf;
+ uint64_t vif_ctrlbuf_toosmall;
};
#ifdef __cplusplus
diff --git a/usr/src/uts/common/sys/pci.h b/usr/src/uts/common/sys/pci.h
index d62d19c3a5..5dd6762ab5 100644
--- a/usr/src/uts/common/sys/pci.h
+++ b/usr/src/uts/common/sys/pci.h
@@ -621,6 +621,8 @@ extern "C" {
#define PCI_CAP_ID_MSI_X 0x11 /* MSI-X supported */
#define PCI_CAP_ID_SATA 0x12 /* SATA Data/Index Config supported */
#define PCI_CAP_ID_FLR 0x13 /* Function Level Reset supported */
+#define PCI_CAP_ID_EA 0x14 /* Enhanced Allocation */
+#define PCI_CAP_ID_FPB 0x15 /* Flattening Portal Bridge */
/*
* Capability next entry pointer values
@@ -909,13 +911,16 @@ typedef struct pcix_attr {
#define PCI_MSI_CTRL 0x02 /* MSI control register, 2 bytes */
#define PCI_MSI_ADDR_OFFSET 0x04 /* MSI 32-bit msg address, 4 bytes */
#define PCI_MSI_32BIT_DATA 0x08 /* MSI 32-bit msg data, 2 bytes */
+#define PCI_MSI_32BIT_EXTDATA 0x0A /* MSI 32-bit msg ext data, 2 bytes */
#define PCI_MSI_32BIT_MASK 0x0C /* MSI 32-bit mask bits, 4 bytes */
#define PCI_MSI_32BIT_PENDING 0x10 /* MSI 32-bit pending bits, 4 bytes */
/*
* PCI Message Signalled Interrupts (MSI) capability entry offsets for 64-bit
*/
+#define PCI_MSI_64BIT_ADDR 0x08 /* MSI 64-bit upper address, 4 bytes */
#define PCI_MSI_64BIT_DATA 0x0C /* MSI 64-bit msg data, 2 bytes */
+#define PCI_MSI_64BIT_EXTDATA 0x0E /* MSI 64-bit msg ext data, 2 bytes */
#define PCI_MSI_64BIT_MASKBITS 0x10 /* MSI 64-bit mask bits, 4 bytes */
#define PCI_MSI_64BIT_PENDING 0x14 /* MSI 64-bit pending bits, 4 bytes */
diff --git a/usr/src/uts/common/sys/pcie.h b/usr/src/uts/common/sys/pcie.h
index e8f91a1390..840c31a328 100644
--- a/usr/src/uts/common/sys/pcie.h
+++ b/usr/src/uts/common/sys/pcie.h
@@ -536,6 +536,7 @@ extern "C" {
#define PCIE_EXT_CAP_NEXT_PTR_MASK 0xFFF
#define PCIE_EXT_CAP_NEXT_PTR_NULL 0x0
+#define PCIE_EXT_CAP_MAX_PTR 0x3c0 /* max. number of caps */
/*
* PCI-Express Enhanced Capability Identifier Values
@@ -559,6 +560,7 @@ extern "C" {
#define PCIE_EXT_CAP_ID_SRIOV 0x10 /* Single Root I/O Virt. */
#define PCIE_EXT_CAP_ID_MRIOV 0x11 /* Multi Root I/O Virt. */
#define PCIE_EXT_CAP_ID_MULTICAST 0x12 /* Multicast Services */
+#define PCIE_EXT_CAP_ID_PGREQ 0x13 /* Page Request */
#define PCIE_EXT_CAP_ID_EA 0x14 /* Enhanced Allocation */
#define PCIE_EXT_CAP_ID_RESIZE_BAR 0x15 /* Resizable BAR */
#define PCIE_EXT_CAP_ID_DPA 0x16 /* Dynamic Power Allocation */
@@ -573,11 +575,15 @@ extern "C" {
#define PCIE_EXT_CAP_ID_FRS 0x21 /* Function Ready Stat. Queue */
#define PCIE_EXT_CAP_ID_RTR 0x22 /* Readiness Time Reporting */
#define PCIE_EXT_CAP_ID_DVS 0x23 /* Designated Vendor-Specific */
+#define PCIE_EXT_CAP_ID_VFRBAR 0x24 /* VF Resizable BAR */
#define PCIE_EXT_CAP_ID_DLF 0x25 /* Data Link Feature */
-#define PCIE_EXT_CAP_ID_PL16GTE 0x26 /* Physical Layer 16.0 GT/s */
+#define PCIE_EXT_CAP_ID_PL16GT 0x26 /* Physical Layer 16.0 GT/s */
#define PCIE_EXT_CAP_ID_LANE_MARGIN 0x27 /* Lane Margining */
#define PCIE_EXT_CAP_ID_HIEARCHY_ID 0x28 /* Hierarchy ID */
#define PCIE_EXT_CAP_ID_NPEM 0x29 /* Native PCIe Enclosure Mgmt */
+#define PCIE_EXT_CAP_ID_PL32GT 0x2A /* Physical Layer 32.0 GT/s */
+#define PCIE_EXT_CAP_ID_AP 0x2B /* Alternate Protocol */
+#define PCIE_EXT_CAP_ID_SFI 0x2C /* Sys. Firmware Intermediary */
/*
* PCI-Express Advanced Error Reporting Extended Capability Offsets
@@ -596,6 +602,7 @@ extern "C" {
#define PCIE_AER_RE_STS 0x30 /* Root Error Status */
#define PCIE_AER_CE_SRC_ID 0x34 /* Error Source ID */
#define PCIE_AER_ERR_SRC_ID 0x36 /* Error Source ID */
+#define PCIE_AER_TLP_PRE_LOG 0x38 /* TLP Prefix Log */
/* Bridges Only */
#define PCIE_AER_SUCE_STS 0x2c /* Secondary UCE Status */
diff --git a/usr/src/uts/i86pc/io/vmm/vmm.c b/usr/src/uts/i86pc/io/vmm/vmm.c
index ad3a9f548f..dac488713a 100644
--- a/usr/src/uts/i86pc/io/vmm/vmm.c
+++ b/usr/src/uts/i86pc/io/vmm/vmm.c
@@ -39,7 +39,7 @@
*
* Copyright 2015 Pluribus Networks Inc.
* Copyright 2021 Joyent, Inc.
- * Copyright 2020 Oxide Computer Company
+ * Copyright 2021 Oxide Computer Company
*/
#include <sys/cdefs.h>
@@ -2933,7 +2933,15 @@ vm_inject_init(struct vm *vm, int vcpuid)
vcpu = &vm->vcpu[vcpuid];
vcpu_lock(vcpu);
vcpu->run_state |= VRS_PEND_INIT;
+ /*
+ * As part of queuing the INIT request, clear any pending SIPI. It
+ * would not otherwise survive across the reset of the vCPU when it
+ * undergoes the requested INIT. We would not want it to linger when it
+ * could be mistaken as a subsequent (after the INIT) SIPI request.
+ */
+ vcpu->run_state &= ~VRS_PEND_SIPI;
vcpu_notify_event_locked(vcpu, VCPU_NOTIFY_EXIT);
+
vcpu_unlock(vcpu);
return (0);
}
diff --git a/usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c b/usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c
index 9267befd19..e668ee35a6 100644
--- a/usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c
+++ b/usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c
@@ -1873,14 +1873,14 @@ vmm_do_vm_destroy_locked(vmm_softc_t *sc, boolean_t clean_zsd,
*hma_release = B_FALSE;
- if (clean_zsd) {
- vmm_zsd_rem_vm(sc);
- }
-
if (vmm_drv_purge(sc) != 0) {
return (EINTR);
}
+ if (clean_zsd) {
+ vmm_zsd_rem_vm(sc);
+ }
+
/* Clean up devmem entries */
vmmdev_devmem_purge(sc);