I thought I'd send this diff out in case it avoids some duplicate work and to solicit feedback about a problem. Comments about the code changes in the update are welcome too.
It does not build as-is, there's an issue with "c_get_text" (a renamed yyget_text) with our version of flex. I have two possible workarounds so far but neither is particularly nice; - add a configlexer.c file generated with newer flex to the tree (e.g. the one included in the upstream distribution) and copy into obj/ before building. (I'm currently running binaries from a build done like this). - backout the changes ("print failed token for config syntax error or parse error") to c_error() / c_error_va_list() in options.c. Release notes since our last update (4.1.3): 4.1.4 Features - RFC7553 RR Type URI support. - removed hardcoded interface limit, --with-max-ips removed. - SO_REUSEPORT support, by default on Linux, or with reuseport: yes. - Admitted axfrs are logged at verbosity 1. Refused at verbosity 2. - --enable-pie and --enable-relro-now options for a safer executable. Bugfixes - Fix NSID response for short edns sizes. - Fix that for expired zones NSD performs an AXFR and accepts newer and older serial numbers. - Document that minimal responses only minimizes responses to fit in one datagram. It does not minimize smaller responses. - Fix #618: documented need to list ip-addresses seperately in nsd.conf if there are multiple, because the source address of replies can otherwise go wrong. - Fix that notify from nsd-control contains soa serial. - Fix #698 formatting errors and typos in nsd.8.in. 4.1.5 - Fix #706: default port 53 not opened on ip4 because of getaddrinfo hints initialisation failure. 4.1.6rc1 - Fix #701: Fix that AD=1 set in a BADVERS response. - Fix typo in zonec.c inside error message. - Fix #711: Document that debug-mode yes is used for staying attached to the supervisor console. - Document verbosity 3 prints more information. - nsd-checkconf warns for master zones with no zonefile statement. - Fix start failure when many file descriptors are in use. - The servfail rcode is not printed with a space in the middle. - print failed token for config syntax error or parse error. Index: acx_nlnetlabs.m4 =================================================================== RCS file: /cvs/src/usr.sbin/nsd/acx_nlnetlabs.m4,v retrieving revision 1.1.1.9 diff -u -p -r1.1.1.9 acx_nlnetlabs.m4 --- acx_nlnetlabs.m4 17 Jul 2015 17:36:01 -0000 1.1.1.9 +++ acx_nlnetlabs.m4 15 Oct 2015 20:47:20 -0000 @@ -2,7 +2,8 @@ # Copyright 2009, Wouter Wijngaards, NLnet Labs. # BSD licensed. # -# Version 27 +# Version 28 +# 2015-08-28 ACX_CHECK_PIE and ACX_CHECK_RELRO_NOW added. # 2015-03-17 AHX_CONFIG_REALLOCARRAY added # 2013-09-19 FLTO help text improved. # 2013-07-18 Enable ACX_CHECK_COMPILER_FLAG to test for -Wstrict-prototypes @@ -94,6 +95,8 @@ # ACX_CHECK_MEMCMP_SIGNED - check if memcmp uses signed characters. # AHX_MEMCMP_BROKEN - replace memcmp func for CHECK_MEMCMP_SIGNED. # ACX_CHECK_SS_FAMILY - check for sockaddr_storage.ss_family +# ACX_CHECK_PIE - add --enable-pie option and check if works +# ACX_CHECK_RELRO_NOW - add --enable-relro-now option and check it # dnl Escape backslashes as \\, for C:\ paths, for the C preprocessor defines. @@ -1385,5 +1388,47 @@ AC_DEFUN([ACX_CHECK_SS_FAMILY], #include <arpa/inet.h> #endif ]) ]) + +dnl Check if CC and linker support -fPIE and -pie. +dnl If so, sets them in CFLAGS / LDFLAGS. +AC_DEFUN([ACX_CHECK_PIE], [ + AC_ARG_ENABLE([pie], AS_HELP_STRING([--enable-pie], [Enable Position-Independent Executable (eg. to fully benefit from ASLR, small performance penalty)])) + AS_IF([test "x$enable_pie" = "xyes"], [ + AC_MSG_CHECKING([if $CC supports PIE]) + BAKLDFLAGS="$LDFLAGS" + BAKCFLAGS="$CFLAGS" + LDFLAGS="$LDFLAGS -pie" + CFLAGS="$CFLAGS -fPIE" + AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])], [ + if $CC $CFLAGS $LDFLAGS -o conftest conftest.c 2>&1 | grep "warning: no debug symbols in executable" >/dev/null; then + LDFLAGS="$BAKLDFLAGS" + AC_MSG_RESULT(no) + else + AC_MSG_RESULT(yes) + fi + rm -f conftest conftest.c conftest.o + ], [LDFLAGS="$BAKLDFLAGS" ; CFLAGS="$BAKCFLAGS" ; AC_MSG_RESULT(no)]) + ]) +]) + +dnl Check if linker supports -Wl,-z,relro,-z,now. +dnl If so, adds it to LDFLAGS. +AC_DEFUN([ACX_CHECK_RELRO_NOW], [ + AC_ARG_ENABLE([relro_now], AS_HELP_STRING([--enable-relro-now], [Enable full relocation binding at load-time (RELRO NOW, to protect GOT and .dtor areas)])) + AS_IF([test "x$enable_relro_now" = "xyes"], [ + AC_MSG_CHECKING([if $CC supports -Wl,-z,relro,-z,now]) + BAKLDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -Wl,-z,relro,-z,now" + AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])], [ + if $CC $CFLAGS $LDFLAGS -o conftest conftest.c 2>&1 | grep "warning: no debug symbols in executable" >/dev/null; then + LDFLAGS="$BAKLDFLAGS" + AC_MSG_RESULT(no) + else + AC_MSG_RESULT(yes) + fi + rm -f conftest conftest.c conftest.o + ], [LDFLAGS="$BAKLDFLAGS" ; AC_MSG_RESULT(no)]) + ]) +]) dnl End of file Index: axfr.c =================================================================== RCS file: /cvs/src/usr.sbin/nsd/axfr.c,v retrieving revision 1.13 diff -u -p -r1.13 axfr.c --- axfr.c 17 Jul 2015 17:36:33 -0000 1.13 +++ axfr.c 15 Oct 2015 20:47:20 -0000 @@ -91,7 +91,7 @@ query_axfr(struct nsd *nsd, struct query query->edns.status = EDNS_NOT_PRESENT; buffer_set_limit(query->packet, QHEADERSZ); QDCOUNT_SET(query->packet, 0); - query_prepare_response(query); + query_prepare_response(query, nsd); } /* Add zone RRs until answer is full. */ @@ -193,6 +193,13 @@ answer_axfr_ixfr(struct nsd *nsd, struct } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "axfr admitted acl %s %s", acl->ip_address_spec, acl->key_name?acl->key_name:"NOKEY")); + if (verbosity >= 1) { + char a[128]; + addr2str(&q->addr, a, sizeof(a)); + VERBOSITY(1, (LOG_INFO, "%s for %s from %s", + (q->qtype==TYPE_AXFR?"axfr":"ixfr"), + dname_to_string(q->qname, NULL), a)); + } return query_axfr(nsd, q); } /** Fallthrough: AXFR over UDP queries are discarded. */ Index: config.h.in =================================================================== RCS file: /cvs/src/usr.sbin/nsd/config.h.in,v retrieving revision 1.18 diff -u -p -r1.18 config.h.in --- config.h.in 17 Jul 2015 17:36:33 -0000 1.18 +++ config.h.in 15 Oct 2015 20:47:20 -0000 @@ -359,9 +359,6 @@ /* Define to the maximum message length to pass to syslog. */ #undef MAXSYSLOGMSGLEN -/* Define to the maximum ip-addresses to serve. */ -#undef MAX_INTERFACES - /* Define if memcmp() does not compare unsigned bytes */ #undef MEMCMP_IS_BROKEN @@ -416,6 +413,9 @@ /* Define as the return type of signal handlers (`int' or `void'). */ #undef RETSIGTYPE + +/* enable reuseport option by default. */ +#undef REUSEPORT_BY_DEFAULT /* Define this to configure as a root server. */ #undef ROOT_SERVER Index: configlexer.lex =================================================================== RCS file: /cvs/src/usr.sbin/nsd/configlexer.lex,v retrieving revision 1.1.1.10 diff -u -p -r1.1.1.10 configlexer.lex --- configlexer.lex 3 Feb 2015 10:24:34 -0000 1.1.1.10 +++ configlexer.lex 15 Oct 2015 20:47:20 -0000 @@ -217,6 +217,7 @@ ipv4-edns-size{COLON} { LEXOUT(("v(%s) " ipv6-edns-size{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_IPV6_EDNS_SIZE;} pidfile{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_PIDFILE;} port{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_PORT;} +reuseport{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_REUSEPORT;} statistics{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_STATISTICS;} chroot{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_CHROOT;} username{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_USERNAME;} Index: configparser.y =================================================================== RCS file: /cvs/src/usr.sbin/nsd/configparser.y,v retrieving revision 1.12 diff -u -p -r1.12 configparser.y --- configparser.y 10 Sep 2015 14:12:38 -0000 1.12 +++ configparser.y 15 Oct 2015 20:47:20 -0000 @@ -67,7 +67,7 @@ extern config_parser_state_t* cfg_parser %token VAR_RRL_IPV4_PREFIX_LENGTH VAR_RRL_IPV6_PREFIX_LENGTH %token VAR_RRL_WHITELIST_RATELIMIT VAR_RRL_WHITELIST %token VAR_ZONEFILES_CHECK VAR_ZONEFILES_WRITE VAR_LOG_TIME_ASCII -%token VAR_ROUND_ROBIN VAR_ZONESTATS +%token VAR_ROUND_ROBIN VAR_ZONESTATS VAR_REUSEPORT %% toplevelvars: /* empty */ | toplevelvars toplevelvar ; @@ -96,7 +96,8 @@ content_server: server_ip_address | serv server_rrl_size | server_rrl_ratelimit | server_rrl_slip | server_rrl_ipv4_prefix_length | server_rrl_ipv6_prefix_length | server_rrl_whitelist_ratelimit | server_zonefiles_check | server_do_ip4 | server_do_ip6 | - server_zonefiles_write | server_log_time_ascii | server_round_robin; + server_zonefiles_write | server_log_time_ascii | server_round_robin | + server_reuseport; server_ip_address: VAR_IP_ADDRESS STRING { OUTYY(("P(server_ip_address:%s)\n", $2)); @@ -189,6 +190,14 @@ server_do_ip6: VAR_DO_IP6 STRING if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) yyerror("expected yes or no."); else cfg_parser->opt->do_ip6 = (strcmp($2, "yes")==0); + } + ; +server_reuseport: VAR_REUSEPORT STRING + { + OUTYY(("P(server_reuseport:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->opt->reuseport = (strcmp($2, "yes")==0); } ; server_database: VAR_DATABASE STRING Index: configure =================================================================== RCS file: /cvs/src/usr.sbin/nsd/configure,v retrieving revision 1.23 diff -u -p -r1.23 configure --- configure 10 Sep 2015 15:49:58 -0000 1.23 +++ configure 15 Oct 2015 20:47:20 -0000 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for NSD 4.1.3. +# Generated by GNU Autoconf 2.69 for NSD 4.1.6. # # Report bugs to <nsd-b...@nlnetlabs.nl>. # @@ -580,8 +580,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='NSD' PACKAGE_TARNAME='nsd' -PACKAGE_VERSION='4.1.3' -PACKAGE_STRING='NSD 4.1.3' +PACKAGE_VERSION='4.1.6' +PACKAGE_STRING='NSD 4.1.6' PACKAGE_BUGREPORT='nsd-b...@nlnetlabs.nl' PACKAGE_URL='' @@ -712,11 +712,12 @@ with_xfrdir with_chroot with_user enable_flto +enable_pie +enable_relro_now with_libevent enable_largefile enable_recvmmsg with_facility -with_max_ips with_tcp_timeout enable_root_server enable_ipv6 @@ -1280,7 +1281,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures NSD 4.1.3 to adapt to many kinds of systems. +\`configure' configures NSD 4.1.6 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1341,7 +1342,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of NSD 4.1.3:";; + short | recursive ) echo "Configuration of NSD 4.1.6:";; esac cat <<\_ACEOF @@ -1350,6 +1351,10 @@ Optional Features: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --disable-flto Disable link-time optimization (gcc specific option) + --enable-pie Enable Position-Independent Executable (eg. to fully + benefit from ASLR, small performance penalty) + --enable-relro-now Enable full relocation binding at load-time (RELRO + NOW, to protect GOT and .dtor areas) --disable-largefile omit support for large files --enable-recvmmsg Enable recvmmsg and sendmmsg compilation, faster but some kernel versions may have implementation @@ -1389,8 +1394,6 @@ Optional Packages: an explicit path), useful when the zone count is high. --with-facility=name Syslog default facility (LOG_DAEMON) - --with-max-ips=number Limit on the number of ip-addresses that may be - specified --with-tcp-timeout=number Limit the default tcp timeout --with-ssl=pathname enable SSL (will check /usr/local/ssl /usr/lib/ssl @@ -1478,7 +1481,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -NSD configure 4.1.3 +NSD configure 4.1.6 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2187,7 +2190,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by NSD $as_me 4.1.3, which was +It was created by NSD $as_me 4.1.6, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -5075,6 +5078,96 @@ rm -f core conftest.err conftest.$ac_obj fi + + # Check whether --enable-pie was given. +if test "${enable_pie+set}" = set; then : + enableval=$enable_pie; +fi + + if test "x$enable_pie" = "xyes"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports PIE" >&5 +$as_echo_n "checking if $CC supports PIE... " >&6; } + BAKLDFLAGS="$LDFLAGS" + BAKCFLAGS="$CFLAGS" + LDFLAGS="$LDFLAGS -pie" + CFLAGS="$CFLAGS -fPIE" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + if $CC $CFLAGS $LDFLAGS -o conftest conftest.c 2>&1 | grep "warning: no debug symbols in executable" >/dev/null; then + LDFLAGS="$BAKLDFLAGS" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + fi + rm -f conftest conftest.c conftest.o + +else + LDFLAGS="$BAKLDFLAGS" ; CFLAGS="$BAKCFLAGS" ; { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +fi + + + # Check whether --enable-relro_now was given. +if test "${enable_relro_now+set}" = set; then : + enableval=$enable_relro_now; +fi + + if test "x$enable_relro_now" = "xyes"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wl,-z,relro,-z,now" >&5 +$as_echo_n "checking if $CC supports -Wl,-z,relro,-z,now... " >&6; } + BAKLDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -Wl,-z,relro,-z,now" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + if $CC $CFLAGS $LDFLAGS -o conftest conftest.c 2>&1 | grep "warning: no debug symbols in executable" >/dev/null; then + LDFLAGS="$BAKLDFLAGS" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + fi + rm -f conftest conftest.c conftest.o + +else + LDFLAGS="$BAKLDFLAGS" ; { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +fi + fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 $as_echo_n "checking for an ANSI C-conforming const... " >&6; } @@ -6380,6 +6473,14 @@ fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +# see if reuseport is enabled by default (also a config option). +# freebsd can compile the option, but it does not work, it works on Linux. +if test "`uname`" = "Linux"; then + +$as_echo "#define REUSEPORT_BY_DEFAULT 1" >>confdefs.h + +fi + # set -I. and -Isrcdir if test -n "$CPPFLAGS"; then CPPFLAGS="$CPPFLAGS -I." @@ -8289,19 +8390,6 @@ cat >>confdefs.h <<_ACEOF _ACEOF -max_ips=32 - -# Check whether --with-max_ips was given. -if test "${with_max_ips+set}" = set; then : - withval=$with_max_ips; max_ips=$withval -fi - - -cat >>confdefs.h <<_ACEOF -#define MAX_INTERFACES $max_ips -_ACEOF - - tcp_timeout=120 # Check whether --with-tcp_timeout was given. @@ -9475,7 +9563,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_wri # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by NSD $as_me 4.1.3, which was +This file was extended by NSD $as_me 4.1.6, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -9537,7 +9625,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -NSD config.status 4.1.3 +NSD config.status 4.1.6 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Index: configure.ac =================================================================== RCS file: /cvs/src/usr.sbin/nsd/configure.ac,v retrieving revision 1.22 diff -u -p -r1.22 configure.ac --- configure.ac 10 Sep 2015 14:12:38 -0000 1.22 +++ configure.ac 15 Oct 2015 20:47:20 -0000 @@ -4,7 +4,7 @@ dnl sinclude(acx_nlnetlabs.m4) -AC_INIT(NSD,4.1.3,nsd-b...@nlnetlabs.nl) +AC_INIT(NSD,4.1.6,nsd-b...@nlnetlabs.nl) AC_CONFIG_HEADER([config.h]) CFLAGS="$CFLAGS" @@ -282,6 +282,8 @@ if test "x$CFLAGS" = "x" ; then # we do not use O3 because it causes miscompilations. ACX_CHECK_COMPILER_FLAG(O2, [CFLAGS="$CFLAGS -O2"]) ACX_CHECK_FLTO + ACX_CHECK_PIE + ACX_CHECK_RELRO_NOW fi AC_C_CONST AC_C_INLINE @@ -502,6 +504,12 @@ AC_CHECK_STRPTIME_WORKS ACX_CHECK_NONBLOCKING_BROKEN ACX_MKDIR_ONE_ARG +# see if reuseport is enabled by default (also a config option). +# freebsd can compile the option, but it does not work, it works on Linux. +if test "`uname`" = "Linux"; then + AC_DEFINE([REUSEPORT_BY_DEFAULT], 1, [enable reuseport option by default.]) +fi + # set -I. and -Isrcdir if test -n "$CPPFLAGS"; then CPPFLAGS="$CPPFLAGS -I." @@ -734,15 +742,6 @@ AC_ARG_WITH([facility], AC_HELP_STRING([--with-facility=name], [Syslog default facility (LOG_DAEMON)]), [facility=$withval]) AC_DEFINE_UNQUOTED([FACILITY], $facility, [Define to the default facility for syslog.]) - -dnl -dnl Determine the maximum number of ip-addresses that are allowed -dnl -max_ips=32 -AC_ARG_WITH([max_ips], - AC_HELP_STRING([--with-max-ips=number], [Limit on the number of ip-addresses that may be specified]), - [max_ips=$withval]) -AC_DEFINE_UNQUOTED([MAX_INTERFACES], $max_ips, [Define to the maximum ip-addresses to serve.]) dnl dnl Determine the default tcp timeout Index: dns.c =================================================================== RCS file: /cvs/src/usr.sbin/nsd/dns.c,v retrieving revision 1.12 diff -u -p -r1.12 dns.c --- dns.c 12 Jan 2015 14:36:48 -0000 1.12 +++ dns.c 15 Oct 2015 20:47:20 -0000 @@ -730,7 +730,9 @@ static rrtype_descriptor_type rrtype_des /* 255 - * [RFC 1035, RFC 6895] */ { 255, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, /* 256 - URI */ - { 256, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } }, + { TYPE_URI, "URI", T_URI, 3, 3, + { RDATA_WF_SHORT, RDATA_WF_SHORT, RDATA_WF_LONG_TEXT }, + { RDATA_ZF_SHORT, RDATA_ZF_SHORT, RDATA_ZF_LONG_TEXT } }, /* 257 - CAA [RFC 6844] */ { TYPE_CAA, "CAA", T_CAA, 3, 3, { RDATA_WF_BYTE, RDATA_WF_TEXT, RDATA_WF_LONG_TEXT }, Index: dns.h =================================================================== RCS file: /cvs/src/usr.sbin/nsd/dns.h,v retrieving revision 1.11 diff -u -p -r1.11 dns.h --- dns.h 18 Dec 2014 23:26:13 -0000 1.11 +++ dns.h 15 Oct 2015 20:47:20 -0000 @@ -154,7 +154,7 @@ typedef enum nsd_rc nsd_rc_type; #define TYPE_MAILB 253 /* A request for mailbox-related records (MB, MG or MR) */ #define TYPE_MAILA 254 /* A request for mail agent RRs (Obsolete - see MX) */ #define TYPE_ANY 255 /* any type (wildcard) */ - +#define TYPE_URI 256 /* RFC 7553 */ #define TYPE_CAA 257 /* RFC 6844 */ #define TYPE_DLV 32769 /* RFC 4431 */ Index: mkinstalldirs =================================================================== RCS file: /cvs/src/usr.sbin/nsd/mkinstalldirs,v retrieving revision 1.3 diff -u -p -r1.3 mkinstalldirs --- mkinstalldirs 26 Nov 2013 12:53:58 -0000 1.3 +++ mkinstalldirs 15 Oct 2015 20:47:20 -0000 @@ -4,7 +4,7 @@ # Created: 1993-05-16 # Public domain -# $Id: mkinstalldirs,v 1.3 2013/11/26 12:53:58 sthen Exp $ +# $Id: mkinstalldirs 2739 2008-06-12 08:10:36Z matje $ errstatus=0 Index: nsd-checkconf.8.in =================================================================== RCS file: /cvs/src/usr.sbin/nsd/nsd-checkconf.8.in,v retrieving revision 1.16 diff -u -p -r1.16 nsd-checkconf.8.in --- nsd-checkconf.8.in 17 Jul 2015 17:36:33 -0000 1.16 +++ nsd-checkconf.8.in 15 Oct 2015 20:47:20 -0000 @@ -1,4 +1,4 @@ -.TH "nsd\-checkconf" "8" "Jun 23, 2015" "NLnet Labs" "nsd 4.1.3" +.TH "nsd\-checkconf" "8" "Oct 15, 2015" "NLnet Labs" "nsd 4.1.6rc1" .\" Copyright (c) 2001\-2008, NLnet Labs. All rights reserved. .\" See LICENSE for the license. .SH "NAME" Index: nsd-checkconf.c =================================================================== RCS file: /cvs/src/usr.sbin/nsd/nsd-checkconf.c,v retrieving revision 1.12 diff -u -p -r1.12 nsd-checkconf.c --- nsd-checkconf.c 17 Jul 2015 17:36:33 -0000 1.12 +++ nsd-checkconf.c 15 Oct 2015 20:47:20 -0000 @@ -344,6 +344,7 @@ config_print_zone(nsd_options_t* opt, co SERV_GET_BIN(debug_mode, o); SERV_GET_BIN(do_ip4, o); SERV_GET_BIN(do_ip6, o); + SERV_GET_BIN(reuseport, o); SERV_GET_BIN(hide_version, o); SERV_GET_BIN(zonefiles_check, o); SERV_GET_BIN(log_time_ascii, o); @@ -440,6 +441,7 @@ config_test_print_server(nsd_options_t* printf("server:\n"); printf("\tdebug-mode: %s\n", opt->debug_mode?"yes":"no"); printf("\tip-transparent: %s\n", opt->ip_transparent?"yes":"no"); + printf("\treuseport: %s\n", opt->reuseport?"yes":"no"); printf("\tdo-ip4: %s\n", opt->do_ip4?"yes":"no"); printf("\tdo-ip6: %s\n", opt->do_ip6?"yes":"no"); printf("\thide-version: %s\n", opt->hide_version?"yes":"no"); @@ -539,18 +541,8 @@ file_inside_chroot(const char* fname, co static int additional_checks(nsd_options_t* opt, const char* filename) { - ip_address_option_t* ip = opt->ip_addresses; zone_options_t* zone; - int num = 0; int errors = 0; - while(ip) { - num++; - ip = ip->next; - } - if(num > MAX_INTERFACES) { - fprintf(stderr, "%s: too many interfaces (ip-address:) specified.\n", filename); - errors ++; - } RBTREE_FOR(zone, zone_options_t*, opt->zone_options) { @@ -563,6 +555,13 @@ additional_checks(nsd_options_t* opt, co fprintf(stderr, "%s: zone %s has allow-notify but no request-xfr" " items. Where can it get a zone transfer when a notify " "is received?\n", filename, zone->name); + errors ++; + } + if(!zone_is_slave(zone) && (!zone->pattern->zonefile || + zone->pattern->zonefile[0] == 0)) { + fprintf(stderr, "%s: zone %s is a master zone but has " + "no zonefile. Where can the data come from?\n", + filename, zone->name); errors ++; } } Index: nsd-checkzone.8.in =================================================================== RCS file: /cvs/src/usr.sbin/nsd/nsd-checkzone.8.in,v retrieving revision 1.1.1.3 diff -u -p -r1.1.1.3 nsd-checkzone.8.in --- nsd-checkzone.8.in 17 Jul 2015 17:36:01 -0000 1.1.1.3 +++ nsd-checkzone.8.in 15 Oct 2015 20:47:20 -0000 @@ -1,4 +1,4 @@ -.TH "nsd\-checkzone" "8" "Jun 23, 2015" "NLnet Labs" "nsd 4.1.3" +.TH "nsd\-checkzone" "8" "Oct 15, 2015" "NLnet Labs" "nsd 4.1.6rc1" .\" Copyright (c) 2014, NLnet Labs. All rights reserved. .\" See LICENSE for the license. .SH "NAME" Index: nsd-control.8.in =================================================================== RCS file: /cvs/src/usr.sbin/nsd/nsd-control.8.in,v retrieving revision 1.4 diff -u -p -r1.4 nsd-control.8.in --- nsd-control.8.in 17 Jul 2015 17:36:33 -0000 1.4 +++ nsd-control.8.in 15 Oct 2015 20:47:20 -0000 @@ -1,4 +1,4 @@ -.TH "nsd\-control" "8" "Jun 23, 2015" "NLnet Labs" "nsd 4.1.3" +.TH "nsd\-control" "8" "Oct 15, 2015" "NLnet Labs" "nsd 4.1.6rc1" .\" Copyright (c) 2011, NLnet Labs. All rights reserved. .\" See LICENSE for the license. .SH "NAME" Index: nsd.8.in =================================================================== RCS file: /cvs/src/usr.sbin/nsd/nsd.8.in,v retrieving revision 1.17 diff -u -p -r1.17 nsd.8.in --- nsd.8.in 3 Feb 2015 11:05:42 -0000 1.17 +++ nsd.8.in 15 Oct 2015 20:47:20 -0000 @@ -1,9 +1,9 @@ -.TH "NSD" "8" "Feb 3, 2015" "NLnet Labs" "NSD 4.1.1" +.TH "NSD" "8" "Oct 15, 2015" "NLnet Labs" "NSD 4.1.6rc1" .\" Copyright (c) 2001\-2008, NLnet Labs. All rights reserved. .\" See LICENSE for the license. .SH "NAME" .B nsd -\- Name Server Daemon (NSD) version 4.1.1. +\- Name Server Daemon (NSD) version 4.1.6rc1. .SH "SYNOPSIS" .B nsd .RB [ \-4 ] @@ -79,8 +79,9 @@ configfile. .P Normally .B NSD -should be started with the `nsd\-control(8) start` command invoked from -.IR /etc/rc.d/nsd . +should be started with the `nsd\-control(8) start` command invoked from a +.I /etc/rc.d/nsd.sh +script or similar at the operating system startup. .TP .B \-4 Only listen to IPv4 connections. @@ -102,7 +103,8 @@ listens to the wildcard interface. .TP .B \-c\fI configfile Read specified -.I configfile instead of the default +.I configfile +instead of the default .IR @nsdconfigfile@ . For format description see nsd.conf(5). .TP @@ -183,7 +185,12 @@ to the daemon periodically. .B \-t\fI chroot Specifies a directory to .I chroot -to upon startup. +to upon startup. This option requires you to ensure that appropriate +syslogd(8) socket (e.g. +.I chrootdir +/dev/log) is available, otherwise +.B NSD +won't produce any log output. .TP .B \-u\fI username Drop user and group privileges to those of @@ -230,6 +237,7 @@ default .B NSD configuration file .SH "DIAGNOSTICS" +.B NSD will log all the problems via the standard syslog(8) .I daemon facility, unless the Index: nsd.c =================================================================== RCS file: /cvs/src/usr.sbin/nsd/nsd.c,v retrieving revision 1.22 diff -u -p -r1.22 nsd.c --- nsd.c 17 Jul 2015 17:36:33 -0000 1.22 +++ nsd.c 15 Oct 2015 20:47:20 -0000 @@ -167,6 +167,28 @@ get_ip_port_frm_str(const char* arg, con *hostname = arg; } +/* append interface to interface array (names, udp, tcp) */ +void +add_interface(char*** nodes, struct nsd* nsd, char* ip) +{ + /* realloc the arrays */ + if(nsd->ifs == 0) { + *nodes = xalloc_zero(sizeof(*nodes)); + nsd->udp = xalloc_zero(sizeof(*nsd->udp)); + nsd->tcp = xalloc_zero(sizeof(*nsd->udp)); + } else { + *nodes = xrealloc(*nodes, (nsd->ifs+1)*sizeof(*nodes)); + nsd->udp = xrealloc(nsd->udp, (nsd->ifs+1)*sizeof(*nsd->udp)); + nsd->tcp = xrealloc(nsd->tcp, (nsd->ifs+1)*sizeof(*nsd->udp)); + (*nodes)[nsd->ifs] = NULL; + memset(&nsd->udp[nsd->ifs], 0, sizeof(*nsd->udp)); + memset(&nsd->tcp[nsd->ifs], 0, sizeof(*nsd->tcp)); + } + + /* add it */ + (*nodes)[nsd->ifs] = ip; + ++nsd->ifs; +} /* * Fetch the nsd parent process id from the nsd pidfile @@ -404,10 +426,9 @@ main(int argc, char *argv[]) struct passwd *pwd = NULL; #endif /* HAVE_GETPWNAM */ - /* For initialising the address info structures */ - /* static so it can get very big without overflowing the stack */ - static struct addrinfo hints[MAX_INTERFACES]; - static const char *nodes[MAX_INTERFACES]; + struct addrinfo hints[2]; + int hints_in_use = 1; + char** nodes = NULL; /* array of address strings, size nsd.ifs */ const char *udp_port = 0; const char *tcp_port = 0; @@ -423,14 +444,11 @@ main(int argc, char *argv[]) nsd.dbfile = 0; nsd.pidfile = 0; nsd.server_kind = NSD_SERVER_MAIN; - - for (i = 0; i < MAX_INTERFACES; i++) { - memset(&hints[i], 0, sizeof(hints[i])); - hints[i].ai_family = DEFAULT_AI_FAMILY; - hints[i].ai_flags = AI_PASSIVE; - nodes[i] = NULL; - } - + memset(&hints, 0, sizeof(*hints)*2); + hints[0].ai_family = DEFAULT_AI_FAMILY; + hints[0].ai_flags = AI_PASSIVE; + hints[1].ai_family = DEFAULT_AI_FAMILY; + hints[1].ai_flags = AI_PASSIVE; nsd.identity = 0; nsd.version = VERSION; nsd.username = 0; @@ -454,7 +472,6 @@ main(int argc, char *argv[]) nsd.identity = IDENTITY; } - /* Parse the command line... */ while ((c = getopt(argc, argv, "46a:c:df:hi:I:l:N:n:P:p:s:u:t:X:V:v" #ifndef NDEBUG /* <mattthijs> only when configured with --enable-checking */ @@ -463,26 +480,17 @@ main(int argc, char *argv[]) )) != -1) { switch (c) { case '4': - for (i = 0; i < MAX_INTERFACES; ++i) { - hints[i].ai_family = AF_INET; - } + hints[0].ai_family = AF_INET; break; case '6': #ifdef INET6 - for (i = 0; i < MAX_INTERFACES; ++i) { - hints[i].ai_family = AF_INET6; - } + hints[0].ai_family = AF_INET6; #else /* !INET6 */ error("IPv6 support not enabled."); #endif /* INET6 */ break; case 'a': - if (nsd.ifs < MAX_INTERFACES) { - nodes[nsd.ifs] = optarg; - ++nsd.ifs; - } else { - error("too many interfaces ('-a') specified."); - } + add_interface(&nodes, &nsd, optarg); break; case 'c': configfile = optarg; @@ -613,29 +621,18 @@ main(int argc, char *argv[]) nsd.options->zonelistfile); } if(nsd.options->do_ip4 && !nsd.options->do_ip6) { - for (i = 0; i < MAX_INTERFACES; ++i) { - hints[i].ai_family = AF_INET; - } + hints[0].ai_family = AF_INET; } #ifdef INET6 if(nsd.options->do_ip6 && !nsd.options->do_ip4) { - for (i = 0; i < MAX_INTERFACES; ++i) { - hints[i].ai_family = AF_INET6; - } + hints[0].ai_family = AF_INET6; } #endif /* INET6 */ if(nsd.options->ip_addresses) { ip_address_option_t* ip = nsd.options->ip_addresses; while(ip) { - if (nsd.ifs < MAX_INTERFACES) { - nodes[nsd.ifs] = ip->address; - ++nsd.ifs; - } else { - error("too many interfaces ('-a' + " - "'ip-address:') specified."); - break; - } + add_interface(&nodes, &nsd, ip->address); ip = ip->next; } } @@ -671,6 +668,11 @@ main(int argc, char *argv[]) if(nsd.child_count == 0) { nsd.child_count = nsd.options->server_count; } +#ifdef SO_REUSEPORT + if(nsd.options->reuseport && nsd.child_count > 1) { + nsd.reuseport = nsd.child_count; + } +#endif /* SO_REUSEPORT */ if(nsd.maximum_tcp_count == 0) { nsd.maximum_tcp_count = nsd.options->tcp_count; } @@ -761,7 +763,7 @@ main(int argc, char *argv[]) /* We need at least one active interface */ if (nsd.ifs == 0) { - nsd.ifs = 1; + add_interface(&nodes, &nsd, NULL); /* * With IPv6 we'd like to open two separate sockets, @@ -778,9 +780,10 @@ main(int argc, char *argv[]) #ifdef INET6 if (hints[0].ai_family == AF_UNSPEC) { #ifdef IPV6_V6ONLY + add_interface(&nodes, &nsd, NULL); hints[0].ai_family = AF_INET6; hints[1].ai_family = AF_INET; - nsd.ifs = 2; + hints_in_use = 2; nsd.grab_ip6_optional = 1; #else /* !IPV6_V6ONLY */ hints[0].ai_family = AF_INET6; @@ -794,14 +797,15 @@ main(int argc, char *argv[]) int r; const char* node = NULL; const char* service = NULL; + int h = ((hints_in_use == 1)?0:i%hints_in_use); /* We don't perform name-lookups */ if (nodes[i] != NULL) - hints[i].ai_flags |= AI_NUMERICHOST; + hints[h].ai_flags |= AI_NUMERICHOST; get_ip_port_frm_str(nodes[i], &node, &service); - hints[i].ai_socktype = SOCK_DGRAM; - if ((r=getaddrinfo(node, (service?service:udp_port), &hints[i], &nsd.udp[i].addr)) != 0) { + hints[h].ai_socktype = SOCK_DGRAM; + if ((r=getaddrinfo(node, (service?service:udp_port), &hints[h], &nsd.udp[i].addr)) != 0) { #ifdef INET6 if(nsd.grab_ip6_optional && hints[0].ai_family == AF_INET6) { log_msg(LOG_WARNING, "No IPv6, fallback to IPv4. getaddrinfo: %s", @@ -815,8 +819,8 @@ main(int argc, char *argv[]) r==EAI_SYSTEM?strerror(errno):""); } - hints[i].ai_socktype = SOCK_STREAM; - if ((r=getaddrinfo(node, (service?service:tcp_port), &hints[i], &nsd.tcp[i].addr)) != 0) { + hints[h].ai_socktype = SOCK_STREAM; + if ((r=getaddrinfo(node, (service?service:tcp_port), &hints[h], &nsd.tcp[i].addr)) != 0) { error("cannot parse address '%s': getaddrinfo: %s %s", nodes[i]?nodes[i]:"(null)", gai_strerror(r), Index: nsd.conf.5.in =================================================================== RCS file: /cvs/src/usr.sbin/nsd/nsd.conf.5.in,v retrieving revision 1.16 diff -u -p -r1.16 nsd.conf.5.in --- nsd.conf.5.in 17 Jul 2015 17:36:33 -0000 1.16 +++ nsd.conf.5.in 15 Oct 2015 20:47:20 -0000 @@ -1,4 +1,4 @@ -.TH "nsd.conf" "5" "Jun 23, 2015" "NLnet Labs" "nsd 4.1.3" +.TH "nsd.conf" "5" "Oct 15, 2015" "NLnet Labs" "nsd 4.1.6rc1" .\" Copyright (c) 2001\-2008, NLnet Labs. All rights reserved. .\" See LICENSE for the license. .SH "NAME" @@ -153,6 +153,13 @@ NSD will bind to the listed ip\-address. to bind multiple ip\-addresses. Optionally, a port number can be given. If none are given NSD listens to the wildcard interface. Same as commandline option .BR \-a. +For servers with multiple IP addresses that can be used to send traffic +to the internet, list them one by one, or the source address of replies +could be wrong. This is because if the udp socket associates a source +address of 0.0.0.0 then the kernel picks an ip-address with which to +send to the internet, and it picks the wrong one. Typically needed for +anycast instances. Use ip-transparent to be able to list addresses that +turn on later (typical for certain load-balancing). .TP .B interface:\fR <ip4 or ip6>[@port] Same as ip\-address (for easy of compatibility with unbound.conf). @@ -162,10 +169,23 @@ Allows NSD to bind to non local addresse listen to IP addresses that are not (yet) added to the network interface, so that it can answer immediately when the address is added. Default is no. .TP +.B reuseport:\fR <yes or no> +Use the SO_REUSEPORT socket option, and create file descriptors for every +server in the server\-count. This improves performance of the network +stack. Only really useful if you also configure a server\-count higher +than 1 (such as, equal to the number of cpus). The default is yes on +Linux (where it works, and has been (backported) to 2.6 and 3.x kernels). +On FreeBSD it is known to fail (default is no), but you can enable it +if you think it is fixed. And a cautious default of no is used for +other systems. +.TP .B debug\-mode:\fR <yes or no> Turns on debugging mode for nsd, does not fork a daemon process. -Default is no. Same as commandline option +Default is no. Same as commandline option .BR \-d. +If set to yes it does not fork and stays in the foreground, which can +be helpful for commandline debugging, but is also used by certain +server supervisor processes to ascertain that the server is running. .TP .B do\-ip4:\fR <yes or no> If yes, NSD listens to IPv4 connections. Default yes. @@ -298,7 +318,8 @@ once per the number of seconds. The defa .B verbosity:\fR <level> This value specifies the verbosity level for (non\-debug) logging. Default is 0. 1 gives more information about incoming notifies and -zone transfers. 2 lists soft warnings that are encountered. +zone transfers. 2 lists soft warnings that are encountered. 3 prints +more information. .IP Verbosity 0 will print warnings and errors, and other events that are important to keep NSD running. Index: nsd.conf.sample.in =================================================================== RCS file: /cvs/src/usr.sbin/nsd/nsd.conf.sample.in,v retrieving revision 1.1.1.11 diff -u -p -r1.1.1.11 nsd.conf.sample.in --- nsd.conf.sample.in 3 Feb 2015 10:24:29 -0000 1.1.1.11 +++ nsd.conf.sample.in 15 Oct 2015 20:47:20 -0000 @@ -17,12 +17,19 @@ server: # uncomment to specify specific interfaces to bind (default are the # wildcard interfaces 0.0.0.0 and ::0). + # For servers with multiple IP addresses, list them one by one, + # or the source address of replies could be wrong. + # Use ip-transparent to be able to list addresses that turn on later. # ip-address: 1.2.3.4 # ip-address: 1.2.3.4@5678 # ip-address: 12fe::8ef0 # Allow binding to non local addresses. Default no. # ip-transparent: no + + # use the reuseport socket option for performance. + # The default is yes on linux, no for others. + # reuseport: no # enable debug mode, does not fork daemon process into the background. # debug-mode: no Index: nsd.h =================================================================== RCS file: /cvs/src/usr.sbin/nsd/nsd.h,v retrieving revision 1.1.1.10 diff -u -p -r1.1.1.10 nsd.h --- nsd.h 17 Jul 2015 17:36:01 -0000 1.1.1.10 +++ nsd.h 15 Oct 2015 20:47:20 -0000 @@ -108,6 +108,7 @@ struct nsd_socket { struct addrinfo * addr; int s; + int fam; }; struct nsd_child @@ -118,6 +119,9 @@ struct nsd_child /* The child's process id. */ pid_t pid; + /* child number in child array */ + int child_num; + /* * Socket used by the parent process to send commands and * receive responses to/from this child process. @@ -198,15 +202,17 @@ struct nsd unsigned char *nsid; uint8_t file_rotation_ok; - /* number of interfaces, ifs < MAX_INTERFACES */ + /* number of interfaces */ size_t ifs; uint8_t grab_ip6_optional; + /* non0 if so_reuseport is in use, if so, tcp, udp array increased */ + int reuseport; - /* TCP specific configuration */ - struct nsd_socket tcp[MAX_INTERFACES]; + /* TCP specific configuration (array size ifs) */ + struct nsd_socket* tcp; - /* UDP specific configuration */ - struct nsd_socket udp[MAX_INTERFACES]; + /* UDP specific configuration (array size ifs) */ + struct nsd_socket* udp; edns_data_type edns_ipv4; #if defined(INET6) Index: options.c =================================================================== RCS file: /cvs/src/usr.sbin/nsd/options.c,v retrieving revision 1.2 diff -u -p -r1.2 options.c --- options.c 10 Sep 2015 14:12:38 -0000 1.2 +++ options.c 15 Oct 2015 20:47:20 -0000 @@ -24,6 +24,7 @@ int c_parse(void); int c_lex(void); int c_wrap(void); void c_error(const char *message); +char* c_get_text(void); static int rbtree_strcmp(const void* p1, const void* p2) @@ -68,6 +69,11 @@ nsd_options_create(region_type* region) opt->pidfile = PIDFILE; opt->port = UDP_PORT; /* deprecated? opt->port = TCP_PORT; */ +#ifdef REUSEPORT_BY_DEFAULT + opt->reuseport = 1; +#else + opt->reuseport = 0; +#endif opt->statistics = 0; opt->chroot = 0; opt->username = USER; @@ -686,19 +692,30 @@ zone_list_close(nsd_options_t* opt) void c_error_va_list(const char* fmt, va_list args) { + char* at = NULL; cfg_parser->errors++; + if((strcmp(fmt, "syntax error") == 0 || strcmp(fmt, "parse error")==0) + && c_get_text() && c_get_text()[0]!=0) { + at = c_get_text(); + } if(cfg_parser->err) { char m[MAXSYSLOGMSGLEN]; - snprintf(m, sizeof(m), "%s:%d: error: ", cfg_parser->filename, + snprintf(m, sizeof(m), "%s:%d: ", cfg_parser->filename, cfg_parser->line); (*cfg_parser->err)(cfg_parser->err_arg, m); + if(at) { + snprintf(m, sizeof(m), "at '%s': ", at); + (*cfg_parser->err)(cfg_parser->err_arg, m); + } + (*cfg_parser->err)(cfg_parser->err_arg, "error: "); vsnprintf(m, sizeof(m), fmt, args); (*cfg_parser->err)(cfg_parser->err_arg, m); (*cfg_parser->err)(cfg_parser->err_arg, "\n"); return; } - fprintf(stderr, "%s:%d: error: ", cfg_parser->filename, - cfg_parser->line); + fprintf(stderr, "%s:%d: ", cfg_parser->filename, cfg_parser->line); + if(at) fprintf(stderr, "at '%s': ", at); + fprintf(stderr, "error: "); vfprintf(stderr, fmt, args); fprintf(stderr, "\n"); } @@ -715,7 +732,9 @@ c_error_msg(const char* fmt, ...) void c_error(const char* str) { - c_error_msg("%s", str); + if(!strchr(str, '%')) + c_error_msg(str); /* so that c_error_va_list can test str */ + else c_error_msg("%s", str); } int Index: options.h =================================================================== RCS file: /cvs/src/usr.sbin/nsd/options.h,v retrieving revision 1.1.1.12 diff -u -p -r1.1.1.12 options.h --- options.h 3 Feb 2015 10:24:31 -0000 1.1.1.12 +++ options.h 15 Oct 2015 20:47:20 -0000 @@ -89,6 +89,7 @@ struct nsd_options { int zonefiles_write; int log_time_ascii; int round_robin; + int reuseport; /** remote control section. enable toggle. */ int control_enable; Index: query.c =================================================================== RCS file: /cvs/src/usr.sbin/nsd/query.c,v retrieving revision 1.17 diff -u -p -r1.17 query.c --- query.c 17 Jul 2015 17:36:33 -0000 1.17 +++ query.c 15 Oct 2015 20:47:20 -0000 @@ -135,6 +135,7 @@ query_error (struct query *q, nsd_rc_typ buffer_clear(q->packet); QR_SET(q->packet); /* This is an answer. */ + AD_CLR(q->packet); RCODE_SET(q->packet, (int) rcode); /* Error code. */ /* Truncate the question as well... */ @@ -1267,7 +1268,7 @@ answer_query(struct nsd *nsd, struct que } void -query_prepare_response(query_type *q) +query_prepare_response(query_type *q, nsd_type *nsd) { uint16_t flags; @@ -1282,6 +1283,9 @@ query_prepare_response(query_type *q) */ q->reserved_space = edns_reserved_space(&q->edns); q->reserved_space += tsig_reserved_space(&q->tsig); + if(q->edns.nsid == 1 && nsd->nsid_len > 0 && + q->edns.status != EDNS_NOT_PRESENT) + q->reserved_space += OPT_HDR + nsd->nsid_len; /* Update the flags. */ flags = FLAGS(q->packet); @@ -1411,7 +1415,7 @@ query_process(query_type *q, nsd_type *n return query_error(q, NSD_RC_OK); } - query_prepare_response(q); + query_prepare_response(q, nsd); if (q->qclass != CLASS_IN && q->qclass != CLASS_ANY) { if (q->qclass == CLASS_CH) { @@ -1450,8 +1454,8 @@ query_add_optional(query_type *q, nsd_ty if (q->edns.dnssec_ok) edns->ok[7] = 0x80; else edns->ok[7] = 0x00; buffer_write(q->packet, edns->ok, OPT_LEN); - if (nsd->nsid_len > 0 && q->edns.nsid == 1 && - !query_overflow_nsid(q, nsd->nsid_len)) { + if (nsd->nsid_len > 0 && q->edns.nsid == 1 && buffer_available( + q->packet, OPT_RDATA+OPT_HDR+nsd->nsid_len)) { /* rdata length */ buffer_write(q->packet, edns->rdata_nsid, OPT_RDATA); /* nsid opt header */ Index: query.h =================================================================== RCS file: /cvs/src/usr.sbin/nsd/query.h,v retrieving revision 1.1.1.5 diff -u -p -r1.1.1.5 query.h --- query.h 26 Nov 2013 12:50:29 -0000 1.1.1.5 +++ query.h 15 Oct 2015 20:47:20 -0000 @@ -191,7 +191,7 @@ query_state_type query_process(query_typ * includes the packet header and question section. Space is reserved * for the optional EDNS record, if required. */ -void query_prepare_response(query_type *q); +void query_prepare_response(query_type *q, nsd_type* nsd); /* * Add EDNS0 information to the response if required. @@ -208,10 +208,5 @@ static inline int query_overflow(query_type *q) { return buffer_position(q->packet) > (q->maxlen - q->reserved_space); -} -static inline int -query_overflow_nsid(query_type *q, uint16_t nsid_len) -{ - return buffer_position(q->packet) > (q->maxlen - q->reserved_space - nsid_len); } #endif /* _QUERY_H_ */ Index: remote.c =================================================================== RCS file: /cvs/src/usr.sbin/nsd/remote.c,v retrieving revision 1.6 diff -u -p -r1.6 remote.c --- remote.c 17 Jul 2015 17:36:33 -0000 1.6 +++ remote.c 15 Oct 2015 20:47:20 -0000 @@ -832,7 +832,7 @@ do_notify(SSL* ssl, xfrd_state_t* xfrd, struct notify_zone_t* n = (struct notify_zone_t*)rbtree_search( xfrd->notify_zones, (const dname_type*)zo->node.key); if(n) { - xfrd_notify_start(n); + xfrd_notify_start(n, xfrd); send_ok(ssl); } else { ssl_printf(ssl, "error zone does not have notify\n"); @@ -840,7 +840,7 @@ do_notify(SSL* ssl, xfrd_state_t* xfrd, } else { struct notify_zone_t* n; RBTREE_FOR(n, struct notify_zone_t*, xfrd->notify_zones) { - xfrd_notify_start(n); + xfrd_notify_start(n, xfrd); } send_ok(ssl); } @@ -1493,7 +1493,7 @@ repat_interrupt_notify_start(xfrd_state_ nz->notify_current = nz->options->pattern->notify; if(nz->notify_restart == 2) { if(nz->notify_restart) - xfrd_notify_start(nz); + xfrd_notify_start(nz, xfrd); } } } Index: server.c =================================================================== RCS file: /cvs/src/usr.sbin/nsd/server.c,v retrieving revision 1.20 diff -u -p -r1.20 server.c --- server.c 17 Jul 2015 17:36:33 -0000 1.20 +++ server.c 15 Oct 2015 20:47:20 -0000 @@ -30,6 +30,7 @@ #include <unistd.h> #include <signal.h> #include <netdb.h> +#include <poll.h> #ifndef SHUT_WR #define SHUT_WR 1 #endif @@ -304,6 +305,7 @@ restart_child_servers(struct nsd *nsd, r nsd->child_count = 0; nsd->server_kind = nsd->children[i].kind; nsd->this_child = &nsd->children[i]; + nsd->this_child->child_num = i; /* remove signal flags inherited from parent the parent will handle them. */ nsd->signal_hint_reload_hup = 0; @@ -546,29 +548,30 @@ initialize_dname_compression_tables(stru compressed_dname_offsets[0] = QHEADERSZ; /* The original query name */ } -/* - * Initialize the server, create and bind the sockets. - * - */ -int -server_init(struct nsd *nsd) +/* create and bind sockets. */ +static int +server_init_ifs(struct nsd *nsd, size_t from, size_t to, int* reuseport_works) { + struct addrinfo* addr; size_t i; -#if defined(SO_REUSEADDR) || (defined(INET6) && (defined(IPV6_V6ONLY) || defined(IPV6_USE_MIN_MTU) || defined(IPV6_MTU) || defined(IP_TRANSPARENT))) +#if defined(SO_REUSEPORT) || defined(SO_REUSEADDR) || (defined(INET6) && (defined(IPV6_V6ONLY) || defined(IPV6_USE_MIN_MTU) || defined(IPV6_MTU) || defined(IP_TRANSPARENT))) int on = 1; #endif /* UDP */ /* Make a socket... */ - for (i = 0; i < nsd->ifs; i++) { - if (!nsd->udp[i].addr) { + for (i = from; i < to; i++) { + /* for reuseports copy socket specs of first entries */ + addr = nsd->udp[i%nsd->ifs].addr; + if (!addr) { nsd->udp[i].s = -1; continue; } - if ((nsd->udp[i].s = socket(nsd->udp[i].addr->ai_family, nsd->udp[i].addr->ai_socktype, 0)) == -1) { + nsd->udp[i].fam = (int)addr->ai_family; + if ((nsd->udp[i].s = socket(addr->ai_family, addr->ai_socktype, 0)) == -1) { #if defined(INET6) - if (nsd->udp[i].addr->ai_family == AF_INET6 && + if (addr->ai_family == AF_INET6 && errno == EAFNOSUPPORT && nsd->grab_ip6_optional) { log_msg(LOG_WARNING, "fallback to UDP4, no IPv6: not supported"); continue; @@ -578,6 +581,22 @@ server_init(struct nsd *nsd) return -1; } +#ifdef SO_REUSEPORT + if(nsd->reuseport && *reuseport_works && + setsockopt(nsd->udp[i].s, SOL_SOCKET, SO_REUSEPORT, + (void*)&on, (socklen_t)sizeof(on)) < 0) { + if(verbosity >= 3 +#ifdef ENOPROTOOPT + || errno != ENOPROTOOPT +#endif + ) + log_msg(LOG_ERR, "setsockopt(..., SO_REUSEPORT, " + "...) failed: %s", strerror(errno)); + *reuseport_works = 0; + } +#else + (void)reuseport_works; +#endif /* SO_REUSEPORT */ #if defined(SO_RCVBUF) || defined(SO_SNDBUF) if(1) { int rcv = 1*1024*1024; @@ -633,7 +652,7 @@ server_init(struct nsd *nsd) #endif /* defined(SO_RCVBUF) || defined(SO_SNDBUF) */ #if defined(INET6) - if (nsd->udp[i].addr->ai_family == AF_INET6) { + if (addr->ai_family == AF_INET6) { # if defined(IPV6_V6ONLY) if (setsockopt(nsd->udp[i].s, IPPROTO_IPV6, IPV6_V6ONLY, @@ -679,7 +698,7 @@ server_init(struct nsd *nsd) } #endif #if defined(AF_INET) - if (nsd->udp[i].addr->ai_family == AF_INET) { + if (addr->ai_family == AF_INET) { # if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) int action = IP_PMTUDISC_DONT; if (setsockopt(nsd->udp[i].s, IPPROTO_IP, @@ -718,7 +737,7 @@ server_init(struct nsd *nsd) #endif /* IP_TRANSPARENT */ } - if (bind(nsd->udp[i].s, (struct sockaddr *) nsd->udp[i].addr->ai_addr, nsd->udp[i].addr->ai_addrlen) != 0) { + if (bind(nsd->udp[i].s, (struct sockaddr *) addr->ai_addr, addr->ai_addrlen) != 0) { log_msg(LOG_ERR, "can't bind udp socket: %s", strerror(errno)); return -1; } @@ -727,14 +746,17 @@ server_init(struct nsd *nsd) /* TCP */ /* Make a socket... */ - for (i = 0; i < nsd->ifs; i++) { - if (!nsd->tcp[i].addr) { + for (i = from; i < to; i++) { + /* for reuseports copy socket specs of first entries */ + addr = nsd->tcp[i%nsd->ifs].addr; + if (!addr) { nsd->tcp[i].s = -1; continue; } - if ((nsd->tcp[i].s = socket(nsd->tcp[i].addr->ai_family, nsd->tcp[i].addr->ai_socktype, 0)) == -1) { + nsd->tcp[i].fam = (int)addr->ai_family; + if ((nsd->tcp[i].s = socket(addr->ai_family, addr->ai_socktype, 0)) == -1) { #if defined(INET6) - if (nsd->tcp[i].addr->ai_family == AF_INET6 && + if (addr->ai_family == AF_INET6 && errno == EAFNOSUPPORT && nsd->grab_ip6_optional) { log_msg(LOG_WARNING, "fallback to TCP4, no IPv6: not supported"); continue; @@ -744,6 +766,20 @@ server_init(struct nsd *nsd) return -1; } +#ifdef SO_REUSEPORT + if(nsd->reuseport && *reuseport_works && + setsockopt(nsd->tcp[i].s, SOL_SOCKET, SO_REUSEPORT, + (void*)&on, (socklen_t)sizeof(on)) < 0) { + if(verbosity >= 3 +#ifdef ENOPROTOOPT + || errno != ENOPROTOOPT +#endif + ) + log_msg(LOG_ERR, "setsockopt(..., SO_REUSEPORT, " + "...) failed: %s", strerror(errno)); + *reuseport_works = 0; + } +#endif /* SO_REUSEPORT */ #ifdef SO_REUSEADDR if (setsockopt(nsd->tcp[i].s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { log_msg(LOG_ERR, "setsockopt(..., SO_REUSEADDR, ...) failed: %s", strerror(errno)); @@ -751,7 +787,7 @@ server_init(struct nsd *nsd) #endif /* SO_REUSEADDR */ #if defined(INET6) - if (nsd->tcp[i].addr->ai_family == AF_INET6) { + if (addr->ai_family == AF_INET6) { # if defined(IPV6_V6ONLY) if (setsockopt(nsd->tcp[i].s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) { @@ -802,7 +838,7 @@ server_init(struct nsd *nsd) #endif /* IP_TRANSPARENT */ } - if (bind(nsd->tcp[i].s, (struct sockaddr *) nsd->tcp[i].addr->ai_addr, nsd->tcp[i].addr->ai_addrlen) != 0) { + if (bind(nsd->tcp[i].s, (struct sockaddr *) addr->ai_addr, addr->ai_addrlen) != 0) { log_msg(LOG_ERR, "can't bind tcp socket: %s", strerror(errno)); return -1; } @@ -818,6 +854,43 @@ server_init(struct nsd *nsd) } /* + * Initialize the server, reuseport, create and bind the sockets. + */ +int +server_init(struct nsd *nsd) +{ + int reuseport_successful = 1; /* see if reuseport works in OS */ + if(nsd->reuseport) { + /* increase the size of the udp and tcp interface arrays, + * there are going to be separate interface file descriptors + * for every server instance */ + nsd->udp = xrealloc(nsd->udp, (nsd->ifs*nsd->reuseport)* + sizeof(*nsd->udp)); + nsd->tcp = xrealloc(nsd->tcp, (nsd->ifs*nsd->reuseport)* + sizeof(*nsd->tcp)); + memset(&nsd->udp[nsd->ifs], 0, sizeof(*nsd->udp)* + (nsd->ifs*(nsd->reuseport-1))); + memset(&nsd->tcp[nsd->ifs], 0, sizeof(*nsd->tcp)* + (nsd->ifs*(nsd->reuseport-1))); + } + + /* open the server interface ports */ + if(server_init_ifs(nsd, 0, nsd->ifs, &reuseport_successful) == -1) + return -1; + + /* continue to open the remaining reuseport ports */ + if(nsd->reuseport && reuseport_successful) { + if(server_init_ifs(nsd, nsd->ifs, nsd->ifs*nsd->reuseport, + &reuseport_successful) == -1) + return -1; + nsd->ifs *= nsd->reuseport; + } else { + nsd->reuseport = 0; + } + return 0; +} + +/* * Prepare the server for take off. * */ @@ -902,7 +975,8 @@ server_close_all_sockets(struct nsd_sock for (i = 0; i < n; ++i) { if (sockets[i].s != -1) { close(sockets[i].s); - freeaddrinfo(sockets[i].addr); + if(sockets[i].addr) + freeaddrinfo(sockets[i].addr); sockets[i].s = -1; } } @@ -1168,16 +1242,14 @@ block_read(struct nsd* nsd, int s, void* { uint8_t* buf = (uint8_t*) p; ssize_t total = 0; - fd_set rfds; - struct timeval tv; - FD_ZERO(&rfds); - + struct pollfd fd; + memset(&fd, 0, sizeof(fd)); + fd.fd = s; + fd.events = POLLIN; + while( total < sz) { ssize_t ret; - FD_SET(s, &rfds); - tv.tv_sec = timeout; - tv.tv_usec = 0; - ret = select(s+1, &rfds, NULL, NULL, timeout==-1?NULL:&tv); + ret = poll(&fd, 1, (timeout==-1)?-1:timeout*1000); if(ret == -1) { if(errno == EAGAIN) /* blocking read */ @@ -1850,7 +1922,7 @@ nsd_child_event_base(void) void server_child(struct nsd *nsd) { - size_t i; + size_t i, from, numifs; region_type *server_region = region_create(xalloc, free); struct event_base* event_base = nsd_child_event_base(); query_type *udp_query; @@ -1862,7 +1934,7 @@ server_child(struct nsd *nsd) } #ifdef RATELIMIT - rrl_init((nsd->this_child - nsd->children)/sizeof(nsd->children[0])); + rrl_init(nsd->this_child->child_num); #endif assert(nsd->server_kind != NSD_SERVER_MAIN); @@ -1893,6 +1965,18 @@ server_child(struct nsd *nsd) log_msg(LOG_ERR, "nsd ipcchild: event_add failed"); } + if(nsd->reuseport) { + numifs = nsd->ifs / nsd->reuseport; + from = numifs * nsd->this_child->child_num; + if(from+numifs > nsd->ifs) { /* should not happen */ + from = 0; + numifs = nsd->ifs; + } + } else { + from = 0; + numifs = nsd->ifs; + } + if (nsd->server_kind & NSD_SERVER_UDP) { #if (defined(NONBLOCKING_IS_BROKEN) || !defined(HAVE_RECVMMSG)) udp_query = query_create(server_region, @@ -1912,7 +1996,7 @@ server_child(struct nsd *nsd) msgs[i].msg_hdr.msg_namelen = queries[i]->addrlen; } #endif - for (i = 0; i < nsd->ifs; ++i) { + for (i = from; i < from+numifs; ++i) { struct udp_handler_data *data; struct event *handler; @@ -1939,15 +2023,15 @@ server_child(struct nsd *nsd) * and disable them based on the current number of active TCP * connections. */ - tcp_accept_handler_count = nsd->ifs; + tcp_accept_handler_count = numifs; tcp_accept_handlers = (struct tcp_accept_handler_data*) region_alloc_array(server_region, - nsd->ifs, sizeof(*tcp_accept_handlers)); + numifs, sizeof(*tcp_accept_handlers)); if (nsd->server_kind & NSD_SERVER_TCP) { - for (i = 0; i < nsd->ifs; ++i) { - struct event *handler = &tcp_accept_handlers[i].event; + for (i = from; i < numifs; ++i) { + struct event *handler = &tcp_accept_handlers[i-from].event; struct tcp_accept_handler_data* data = - &tcp_accept_handlers[i]; + &tcp_accept_handlers[i-from]; data->nsd = nsd; data->socket = &nsd->tcp[i]; event_set(handler, nsd->tcp[i].s, EV_PERSIST|EV_READ, @@ -2060,9 +2144,9 @@ handle_udp(int fd, short event, void* ar /* Account... */ #ifdef BIND8_STATS - if (data->socket->addr->ai_family == AF_INET) { + if (data->socket->fam == AF_INET) { STATUP(data->nsd, qudp); - } else if (data->socket->addr->ai_family == AF_INET6) { + } else if (data->socket->fam == AF_INET6) { STATUP(data->nsd, qudp6); } #endif @@ -2078,9 +2162,9 @@ handle_udp(int fd, short event, void* ar } #ifdef USE_ZONE_STATS - if (data->socket->addr->ai_family == AF_INET) { + if (data->socket->fam == AF_INET) { ZTATUP(data->nsd, q->zone, qudp); - } else if (data->socket->addr->ai_family == AF_INET6) { + } else if (data->socket->fam == AF_INET6) { ZTATUP(data->nsd, q->zone, qudp6); } #endif @@ -2218,9 +2302,9 @@ handle_udp(int fd, short event, void* ar #endif /* NONBLOCKING_IS_BROKEN || !HAVE_RECVMMSG */ /* Account... */ - if (data->socket->addr->ai_family == AF_INET) { + if (data->socket->fam == AF_INET) { STATUP(data->nsd, qudp); - } else if (data->socket->addr->ai_family == AF_INET6) { + } else if (data->socket->fam == AF_INET6) { STATUP(data->nsd, qudp6); } @@ -2235,9 +2319,9 @@ handle_udp(int fd, short event, void* ar } #ifdef USE_ZONE_STATS - if (data->socket->addr->ai_family == AF_INET) { + if (data->socket->fam == AF_INET) { ZTATUP(data->nsd, q->zone, qudp); - } else if (data->socket->addr->ai_family == AF_INET6) { + } else if (data->socket->fam == AF_INET6) { ZTATUP(data->nsd, q->zone, qudp6); } #endif Index: util.c =================================================================== RCS file: /cvs/src/usr.sbin/nsd/util.c,v retrieving revision 1.17 diff -u -p -r1.17 util.c --- util.c 17 Jul 2015 17:36:33 -0000 1.17 +++ util.c 15 Oct 2015 20:47:20 -0000 @@ -1014,7 +1014,7 @@ rcode2str(int rc) case RCODE_FORMAT: return "FORMAT ERROR"; case RCODE_SERVFAIL: - return "SERV FAIL"; + return "SERVFAIL"; case RCODE_NXDOMAIN: return "NAME ERROR"; case RCODE_IMPL: @@ -1030,6 +1030,7 @@ rcode2str(int rc) case RCODE_NOTAUTH: return "SERVER NOT AUTHORITATIVE FOR ZONE"; case RCODE_NOTZONE: + /* Name not contained in zone */ return "NOTZONE"; default: return "UNKNOWN ERROR"; Index: xfrd-notify.c =================================================================== RCS file: /cvs/src/usr.sbin/nsd/xfrd-notify.c,v retrieving revision 1.1.1.7 diff -u -p -r1.1.1.7 xfrd-notify.c --- xfrd-notify.c 26 Nov 2013 12:50:15 -0000 1.1.1.7 +++ xfrd-notify.c 15 Oct 2015 20:47:20 -0000 @@ -325,11 +325,15 @@ notify_enable(struct notify_zone_t* zone } void -xfrd_notify_start(struct notify_zone_t* zone) +xfrd_notify_start(struct notify_zone_t* zone, struct xfrd_state* xfrd) { + xfrd_zone_t* xz; if(zone->is_waiting || zone->notify_send_enable) return; - notify_enable(zone, NULL); + xz = (xfrd_zone_t*)rbtree_search(xfrd->zones, zone->apex); + if(xz && xz->soa_nsd_acquired) + notify_enable(zone, &xz->soa_nsd); + else notify_enable(zone, NULL); } void Index: xfrd-notify.h =================================================================== RCS file: /cvs/src/usr.sbin/nsd/xfrd-notify.h,v retrieving revision 1.1.1.7 diff -u -p -r1.1.1.7 xfrd-notify.h --- xfrd-notify.h 13 Mar 2014 02:00:28 -0000 1.1.1.7 +++ xfrd-notify.h 15 Oct 2015 20:47:20 -0000 @@ -73,7 +73,7 @@ void xfrd_del_notify(struct xfrd_state* void xfrd_send_notify(rbtree_t* tree, const struct dname* apex, struct xfrd_soa* new_soa); /* start notifications, if not started already (does not clobber SOA) */ -void xfrd_notify_start(struct notify_zone_t* zone); +void xfrd_notify_start(struct notify_zone_t* zone, struct xfrd_state* xfrd); /* handle soa update notify for a master zone. newsoa can be NULL. Makes sure that the soa (serial) has changed. Or drops notify. */ Index: xfrd-tcp.c =================================================================== RCS file: /cvs/src/usr.sbin/nsd/xfrd-tcp.c,v retrieving revision 1.12 diff -u -p -r1.12 xfrd-tcp.c --- xfrd-tcp.c 10 Feb 2015 22:06:38 -0000 1.12 +++ xfrd-tcp.c 15 Oct 2015 20:47:20 -0000 @@ -568,7 +568,10 @@ xfrd_tcp_setup_write_packet(struct xfrd_ assert(zone->tcp_waiting == 0); /* start AXFR or IXFR for the zone */ if(zone->soa_disk_acquired == 0 || zone->master->use_axfr_only || - zone->master->ixfr_disabled) { + zone->master->ixfr_disabled || + /* if zone expired, after the first round, do not ask for + * IXFR any more, but full AXFR (of any serial number) */ + (zone->state == xfrd_zone_expired && zone->round_num != 0)) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "request full zone transfer " "(AXFR) for %s to %s", zone->apex_str, zone->master->ip_address_spec)); Index: zonec.c =================================================================== RCS file: /cvs/src/usr.sbin/nsd/zonec.c,v retrieving revision 1.16 diff -u -p -r1.16 zonec.c --- zonec.c 10 Sep 2015 14:12:38 -0000 1.16 +++ zonec.c 15 Oct 2015 20:47:20 -0000 @@ -1449,7 +1449,7 @@ process_rr(void) return 0; } if(rrset->rr_count == 65535) { - zc_error_prev_line("too may RRs for domain RRset"); + zc_error_prev_line("too many RRs for domain RRset"); return 0; } Index: zparser.y =================================================================== RCS file: /cvs/src/usr.sbin/nsd/zparser.y,v retrieving revision 1.11 diff -u -p -r1.11 zparser.y --- zparser.y 17 Jul 2015 17:36:33 -0000 1.11 +++ zparser.y 15 Oct 2015 20:47:20 -0000 @@ -66,7 +66,7 @@ nsec3_add_params(const char* hash_algo_s %token <type> T_GPOS T_EID T_NIMLOC T_ATMA T_NAPTR T_KX T_A6 T_DNAME T_SINK %token <type> T_OPT T_APL T_UINFO T_UID T_GID T_UNSPEC T_TKEY T_TSIG T_IXFR %token <type> T_AXFR T_MAILB T_MAILA T_DS T_DLV T_SSHFP T_RRSIG T_NSEC T_DNSKEY -%token <type> T_SPF T_NSEC3 T_IPSECKEY T_DHCID T_NSEC3PARAM T_TLSA +%token <type> T_SPF T_NSEC3 T_IPSECKEY T_DHCID T_NSEC3PARAM T_TLSA T_URI %token <type> T_NID T_L32 T_L64 T_LP T_EUI48 T_EUI64 T_CAA T_CDS T_CDNSKEY /* other tokens */ @@ -632,6 +632,8 @@ type_and_rdata: | T_CDS sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_CDNSKEY sp rdata_dnskey | T_CDNSKEY sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_URI sp rdata_uri + | T_URI sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_UTYPE sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | STR error NL { @@ -1027,6 +1029,15 @@ rdata_eui48: STR trail rdata_eui64: STR trail { zadd_rdata_wireformat(zparser_conv_eui(parser->region, $1.str, 64)); + } + ; + +/* RFC7553 */ +rdata_uri: STR sp STR sp STR trail + { + zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* priority */ + zadd_rdata_wireformat(zparser_conv_short(parser->region, $3.str)); /* weight */ + zadd_rdata_wireformat(zparser_conv_long_text(parser->region, $5.str, $5.len)); /* target */ } ;